移动安全 安全管理 应用案例 网络威胁 系统安全应用安全 数据安全 云安全
当前位置: 主页 > 信息安全 > 应用安全 >

若何安然的存储用户的暗码(三)

时间:2014-03-17 13:49来源:TuZhiJiaMi企业信息安全专家 点击:
大年夜大都的web开辟者城市碰着设计用户账号系统的需求。账号系统最首要的一个方面就是若何呵护用户的暗码。一些大公司的用户数据库泄漏事务也时有产生,所以我们必需采纳一些办法来
Tags应用安全(1006)安全密码(6)存储用户(3)  

  大年夜大都的web开辟者城市碰着设计用户账号系统的需求。账号系统最首要的一个方面就是若何呵护用户的暗码。一些大公司的用户数据库泄漏事务也时有产生,所以我们必需采纳一些办法来呵护用户的暗码,即便网站被攻破的环境下也不会造成较大年夜的风险。

  java PBKDF2 暗码hash代码

  代码下载

  /*

  * Password Hashing With PBKDF2 (http://crackstation.net/hashing-security.htm).

  * Copyright (c) 2013, Taylor Hornby

  * All rights reserved.

  *

  * Redistribution and use in source and binary forms, with or without

  * modification, are permitted provided that the following conditions are met:

  *

  * 1. Redistributions of source code must retain the above copyright notice,

  * this list of conditions and the following disclaimer.

  *

  * 2. Redistributions in binary form must reproduce the above copyright notice,

  * this list of conditions and the following disclaimer in the documentation

  * and/or other materials provided with the distribution.

  *

  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"

  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE

  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE

  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE

  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR

  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF

  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS

  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN

  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)

  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE

  * POSSIBILITY OF SUCH DAMAGE.

  */

  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!");

   大年夜大都的web开辟者城市碰着设计用户账号系统的需求。账号系统最首要的一个方面就是若何呵护用户的暗码。一些大公司的用户数据库泄漏事务也时有产生,所以我们必需采纳一些办法来呵护用户的暗码,即便网站被攻破的环境下也不会造成较大年夜的风险。

  Ruby (on Rails) 暗码hash代码

  代码下载

  # Password Hashing With PBKDF2 (http://crackstation.net/hashing-security.htm).

  # Copyright (c) 2013, Taylor Hornby

  # All rights reserved.

  #

  # Redistribution and use in source and binary forms, with or without

  # modification, are permitted provided that the following conditions are met:

  #

  # 1. Redistributions of source code must retain the above copyright notice,

  # this list of conditions and the following disclaimer.

  #

  # 2. Redistributions in binary form must reproduce the above copyright notice,

  # this list of conditions and the following disclaimer in the documentation

  # and/or other materials provided with the distribution.

  #

  # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"

  # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE

  # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE

  # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE

  # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR

  # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF

  # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS

  # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN

  # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)

  # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE

  # POSSIBILITY OF SUCH DAMAGE.

  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 )

------分隔线----------------------------

推荐内容