如何安全的存储用户密码?(下)代码实现pbkdf2算法加密

这辈子没办法做太多事情,所以每一件都要做到精彩绝伦!

People can‘t do too many things in my life,so everything will be wonderful   乔布斯

本文参考博客:

http://wyait.blog.51cto.com/12674066/1918470

http://wyait.blog.51cto.com/12674066/1918474

参考资料:java API6.0中文版.chm

本文以java为例,进行实际加解密操作:

1       密码加盐hash

使用salt+password进行哈希算法加密!哈希算法选择:PBKDF2!

1.1    生成salt

使用随机函数java.security.SecureRandom生成24位随机数作为salt:

本文参考的依据是:JDK API 1.6.0 中文版,下载地址:http://down.51cto.com/data/2300228

1.2    PBKDF2代码详解

可以直接copy到代码中

package com.demo.encrypt;

/*

*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 "ASIS"

*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.math.BigInteger;

importjava.security.NoSuchAlgorithmException;

import java.security.SecureRandom;

import java.security.spec.InvalidKeySpecException;

import javax.crypto.SecretKeyFactory;

import javax.crypto.spec.PBEKeySpec;

/*

*PBKDF2 salted password hashing.

*Author: havoc AT defuse.ca

*www: http://crackstation.net/hashing-security.htm

*/

public class HashEncrypt {

//PBKDF2.PBKDF2WithHmacSHA1, PBKDF2.PBKDF2WithHmacSHA224,PBKDF2.PBKDF2WithHmacSHA256,

//PBKDF2.PBKDF2WithHmacSHA384,//PBKDF2.PBKDF2WithHmacSHA512

//pbkdf2算法API链接:http://javadoc.iaik.tugraz.at/iaik_jce/current/iaik/pkcs/pkcs5/PBKDF2.html

publicstatic final String PBKDF2_ALGORITHM = "PBKDF2WithHmacSHA1";

//publicstatic final String PBKDF2_ALGORITHM = "PBKDF2WithHmacSHA256";

//注意jdk1.8以下版本不支持SHA224以及SHA224以上算法,会报错:(项目环境为JDK1.7)

//ERROR:java.security.NoSuchAlgorithmException: PBKDF2WithHmacSHA224 SecretKeyFactorynot available

//The following constants may be changed without breaking existing hashes.

publicstatic final int SALT_BYTE_SIZE = 16;//=32/2,生成字符长度为32的salt值

publicstatic final int HASH_BYTE_SIZE = 24;

publicstatic final int PBKDF2_ITERATIONS = 1000;

publicstatic final int ITERATION_INDEX = 0;

publicstatic final int SALT_INDEX = 1;

publicstatic final int PBKDF2_INDEX = 2;

/**

* Returns a salted PBKDF2 hash of thepassword.(返回使用PBKDF2对password进行加盐hash生成的字符串)

*

* @param  password    the password to hash

* @return              a salted PBKDF2 hash of thepassword

*/

publicstatic String createHash(String password)

throwsNoSuchAlgorithmException, InvalidKeySpecException {

returncreateHash(password.toCharArray());

}

/**

* Returns a salted PBKDF2 hash of thepassword.(返回使用PBKDF2对password字节数组进行加盐hash生成的字符串)

*

* @param  password    the password to hash

* @return              a salted PBKDF2 hash of thepassword

*/

publicstatic String createHash(char[] password)

throwsNoSuchAlgorithmException, InvalidKeySpecException {

LongstartTime = System.currentTimeMillis();

//Generate a random salt:创建一个随机16位盐

SecureRandomrandom = 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);

LongendTime = System.currentTimeMillis();

System.out.println("生成加盐hash密码时间是:"+ String.valueOf(endTime - startTime));

//format iterations:salt:hash:对字节数组进行hash返回字符串,字符串结构:(迭代次数:salt盐:加盐hash密码)

returnPBKDF2_ITERATIONS + ":" + toHex(salt) + ":" + toHex(hash);

}

/**

* Validates a password using a hash.(校验密码是否正确)

*

* @param  password        the password tocheck

* @param  correctHash     the hash of thevalid password

* @return                  true if the password iscorrect, false if not

*/

publicstatic boolean validatePassword(String password, String correctHash)

throwsNoSuchAlgorithmException, InvalidKeySpecException {

returnvalidatePassword(password.toCharArray(), correctHash);

}

/**

* Validates a password using a hash.(校验密码是否正确实现)

*

* @param  password        the password tocheck

* @param  correctHash     the hash of thevalid password

* @return                  true if the password iscorrect, false if not:校验密码是否正确

*/

publicstatic boolean validatePassword(char[] password, String correctHash)

throwsNoSuchAlgorithmException, InvalidKeySpecException {

//correctHash字符串的结构为(迭代次数:salt盐:加盐hash密码)

//Decode the hash into its parameters:冒号分隔correctHash

String[]params = correctHash.split(":");

//params[0]:迭代次数

intiterations = Integer.parseInt(params[ITERATION_INDEX]);

//params[1]:salt盐 ,再转换为字节数组

byte[]salt = fromHex(params[SALT_INDEX]);

////params[2]:加盐hash密码字符串,再转换为字节数组

byte[]hash = fromHex(params[PBKDF2_INDEX]);

//Compute the hash of the provided password, using the same salt,

//iteration count, and hash length :使用password生成密钥

byte[]testHash = pbkdf2(password, salt, iterations, hash.length);

//Compare the hashes in constant time. The password is correct if

//both hashes match.:比较密钥是否相等

returnslowEquals(hash, testHash);

}

/**

* Compares two byte arrays in length-constanttime. This comparison method

* is used so that password hashes cannot beextracted from an on-line

* system using a timing attack and thenattacked off-line.

* 这段代码使用了异或(XOR)操作符”^”来比较整数是否相等,而没有使用”==”操作符。原因在于如果两个数完全一致,异或之后的值为零。

*
因为 0 XOR 0 = 0, 1 XOR1 = 0, 0 XOR 1 = 1, 1 XOR 0 = 1。

*
所以,第一行代码如果a.length等于b.length,变量diff等于0,否则的话diff就是一个非零的值。

*
然后,让a,b的每一个字节XOR之后再跟diff OR。这样,只有diff一开始是0,并且,a,b的每一个字节XOR的结果也是零,

*
最后循环完成后diff的值才是0,这种情况是a,b完全一样。否则最后diff是一个非零的值。

*

* @param  a       the first byte array

* @param  b       the second byte array

* @return          true if both byte arrays are thesame, false if not:比较两个字节数组是否相等。0相等;1不等

*/

privatestatic boolean slowEquals(byte[] a, byte[] b) {

intdiff = a.length ^ b.length;

for(int i = 0; i < a.length && i < b.length; i++)

diff|= a[i] ^ b[i];

returndiff == 0;

}

/**

* Computes the PBKDF2 hash of a password.(使用pbkdf2算法生成加盐hash字节数组)

*

* @param  password    the password to hash.

* @param  salt        the salt

* @param  iterations  the iteration count(slowness factor)

* @param  bytes       the length of the hashto compute in bytes

* @return              the PBDKF2 hash of the password:使用pbkdf2进行加盐hash生成密钥

*/

privatestatic byte[] pbkdf2(char[] password, byte[] salt, int iterations,

intbytes) throws NoSuchAlgorithmException, InvalidKeySpecException {

//PBEKeySpec:可随同基于密码的加密法 (PBE)

//使用的供用户选择的密码。可以将密码视为某种原始密钥内容,由此加密机制使用其导出一个密钥。

//带有生成可变密钥大小的 PBE 密码的 PBEKey 时使用的一个密码、salt、迭代计数以及导出密钥长度的构造方法。如果指定

//password 为 null,则使用一个空 char[]。

//注:在将 password 和 salt 存储进新的 PBEKeySpec 对象前将其复制。

//参数:

//password - 密码。

//salt - salt。

//iterationCount - 迭代计数。

//keyLength - 要导出的密钥长度。

PBEKeySpecspec = new PBEKeySpec(password, salt, iterations, bytes * 8);

//SecretKeyFactory此类表示秘密密钥的工厂。

//getInstance(String PBKDF2_ALGORITHM)返回转换指定算法的秘密密钥的SecretKeyFactory

//对象。

//PBKDF2_ALGORITHM = "PBKDF2WithHmacSHA1";

SecretKeyFactoryskf = SecretKeyFactory.getInstance(PBKDF2_ALGORITHM);

//skf.generateSecret(spec)根据提供的密钥规范(密钥材料)生成 SecretKey 对象。

//SecretKey.getEncoded()返回基本编码格式的密钥,如果此密钥不支持编码,则返回 null。

returnskf.generateSecret(spec).getEncoded();

}

/**

* Converts a string of hexadecimal charactersinto a byte array.(将十六进制字符串转换为字节数组)

*

* @param  hex         the hex string

* @return              the hex string decoded into abyte array:字符串转换为字节数组

*/

privatestatic 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);

}

returnbinary;

}

/**

* Converts a byte array into a hexadecimalstring.(将字节数组转换为十六进制字符串)

*

* @param  array       the byte array toconvert

* @return              a length*2 character stringencoding the byte array::字节数组转换为字符串

*/

privatestatic String toHex(byte[] array) {

BigIntegerbi = new BigInteger(1, array);

Stringhex = bi.toString(16);

intpaddingLength = (array.length * 2) - hex.length();

if(paddingLength > 0)

returnString.format("%0" + paddingLength + "d", 0) + hex;

else

returnhex;

}

/**

* Tests the basic functionality of thePasswordHash class

*

* @param  args        ignored

*/

publicstatic void main(String[] args) {

try{

//Print out 10 hashes

for(int i = 0; i < 10; i++) {

//System.out.println(HashEncrypt.createHash("p\\r\\nassw0Rd!"));

System.out.println("生成加盐hash后密钥:第" +i + "次:hashPWd:"

+HashEncrypt.createHash("p\\r\\nassw0Rd!"));

}

//Test password validation

booleanfailure = false;

System.out.println("Runningtests...");

for(int i = 0; i < 2; i++) {

Stringpassword = "" + i;

Stringhash = createHash(password);

System.out.println("password第一次加盐hash:"+ hash);

StringsecondHash = createHash(password);

System.out.println("password第二次加盐hash:"+ secondHash);

if(hash.equals(secondHash)) {

//System.out.println("FAILURE: TWO HASHES ARE EQUAL!");

System.out.println("password="+ i

+",加盐hash后生成的两个密钥相等!就不可用!");

failure= true;

}

StringwrongPassword = "" + (i + 1);

if(validatePassword(wrongPassword, hash)) {

//System.out.println("FAILURE: WRONG PASSWORD ACCEPTED!");

System.out.println("hash="+ hash + ",wrongPassword="

+wrongPassword + ",校验密钥匹配!就不可用!");

failure= true;

}

if(!validatePassword(password, hash)) {

System.out.println("FAILURE:GOOD PASSWORD NOT ACCEPTED!");

System.out.println("hash=" +hash + ",password=" + password

+",校验密钥不匹配,hash就是password生成的!就不可用!");

failure= true;

}

}

if(failure)

System.out.println("TESTSFAILED!");

else

System.out.println("TESTSPASSED!");

}catch (Exception ex) {

System.out.println("ERROR:" + ex);

}

}

}

1.3    PBKDF2项目实践

1,  用户注册,使用PBKDF2对密码进行加盐hash加密;

2,  将salt盐和生成的hash密码存入数据库中;

3,  用户登录对密码进行加盐hash;

4,  校验密码;

5,  用户每次登录,重复3/4步骤。

如果想保存32位固定长度密码,可以在后面再进行一次MD5加密

工具类:

package com. common.utils;

import java.math.BigInteger;

import java.security.NoSuchAlgorithmException;

import java.security.SecureRandom;

importjava.security.spec.InvalidKeySpecException;

import javax.crypto.SecretKeyFactory;

import javax.crypto.spec.PBEKeySpec;

/**

*

* @项目名称:common

* @类名称:HashEncrypt

* @类描述:使用PBKDF2对密码进行加密处理

* @创建人:wyait

* @创建时间:2017年4月24日 上午9:53:15

*@version:

*/

public class HashEncrypt {

//pbkdf2 SHA1算法(由于JDK1.8以下只能使用SHA1,so....这将会是个历史遗留问题)

publicstatic final String PBKDF2_ALGORITHM = "PBKDF2WithHmacSHA1";

//=32/2,生成字符长度为32的salt值

publicstatic final int SALT_BYTE_SIZE = 16;

//48/2,生成字符长度为48的hash密码

publicstatic final int HASH_BYTE_SIZE = 24;

//加密迭代次数

publicstatic final int PBKDF2_ITERATIONS = 1000;

/**

*

* @描述:返回使用SecureRandom生成salt盐

* @创建人:wyait

* @创建时间:2017年4月24日 上午10:40:14

* @return

*/

publicstatic String createSalt() {

//Generate a random salt:创建一个随机16位盐

SecureRandomrandom = new SecureRandom();

byte[]salt = new byte[SALT_BYTE_SIZE];

random.nextBytes(salt);

//转换为十六进制字符串,字符长度=32

returntoHex(salt);

}

/**

*

* @描述:返回使用PBKDF2对password进行加盐hash生成的字符串(字符长度48)

* @创建人:wyait

* @创建时间:2017年4月24日 上午9:55:37

* @param salt 盐

* @param password  原始密码

* @return

* @throws NoSuchAlgorithmException

* @throws InvalidKeySpecException

*/

publicstatic String createHash(String salt, String password)

throwsNoSuchAlgorithmException, InvalidKeySpecException {

returncreateHash(fromHex(salt), password.toCharArray());

}

/**

*

* @描述:返回使用PBKDF2对password字节数组进行加盐hash生成的字符串(字符长度48)

* @创建人:wyait

* @创建时间:2017年4月24日 上午9:57:35

* @param salt 盐转换为字节数组

* @param password 密码转换为字符数组

* @return

* @throws NoSuchAlgorithmException

* @throws InvalidKeySpecException

*/

publicstatic String createHash(byte[] salt, char[] password)

throwsNoSuchAlgorithmException, InvalidKeySpecException {

//Hash the password :hash生成字节数组

byte[]hash = pbkdf2(password, salt, PBKDF2_ITERATIONS, HASH_BYTE_SIZE);

//对字节数组进行hash返回字符串(加盐hash密码)

System.out.println("hash密钥字符串长度:"+ toHex(hash).length());

returntoHex(hash);

}

/**

*

* @描述:校验密码是否正确

* @创建人:wyait

* @创建时间:2017年4月24日 上午10:02:49

* @param salt 盐

* @param password  密码

* @param correctHash  加盐hash密码

* @return

* @throws NoSuchAlgorithmException

* @throws InvalidKeySpecException

*/

publicstatic boolean validatePassword(String salt, String password,

StringcorrectHash) throws NoSuchAlgorithmException,

InvalidKeySpecException{

returnvalidatePassword(fromHex(salt), password.toCharArray(),

correctHash);

}

/**

*

* @描述:校验密码是否正确实现

* @创建人:wyait

* @创建时间:2017年4月24日 上午10:07:14

* @param salt  盐

* @param password   密码

* @param correctHash   加盐hash密码

* @return

* @throws NoSuchAlgorithmException

* @throws InvalidKeySpecException

*/

publicstatic boolean validatePassword(byte[] salt, char[] password,

StringcorrectHash) throws NoSuchAlgorithmException,

InvalidKeySpecException{

//将correctHash转换为字节数组

byte[]hash = fromHex(correctHash);

//对passwrod进行:加盐hash生成密码字符串,再比对correctHash

byte[]testHash = pbkdf2(password, salt, PBKDF2_ITERATIONS, hash.length);

//both hashes match.:比较密钥是否相等

returnslowEquals(hash, testHash);

}

/**

*

* @描述:比较两个字节数组的值是否相等

* @创建人:wyait

* @创建时间:2017年4月24日 上午10:07:46

* @param a

* @param b

* @return

*/

privatestatic boolean slowEquals(byte[] a, byte[] b) {

intdiff = a.length ^ b.length;

for(int i = 0; i < a.length && i < b.length; i++)

diff|= a[i] ^ b[i];

returndiff == 0;

}

/**

*

* @描述:使用pbkdf2算法生成加盐hash字节数组

* @创建人:wyait

* @创建时间:2017年4月24日 上午10:11:02

* @param password

* @param salt

* @param iterations

* @param bytes

* @return

* @throws NoSuchAlgorithmException

* @throws InvalidKeySpecException

*/

privatestatic byte[] pbkdf2(char[] password, byte[] salt, int iterations,

intbytes) throws NoSuchAlgorithmException, InvalidKeySpecException {

//PBEKeySpec:

//带有生成可变密钥大小的 PBE 密码的 PBEKey 时使用的一个密码、salt、迭代计数以及导出密钥长度的构造方法。如果指定

//password 为 null,则使用一个空 char[]。

//注:在将 password 和 salt 存储进新的 PBEKeySpec 对象前将其复制。

//参数:

//password - 密码。

//salt - salt。

//iterationCount - 迭代计数。

//keyLength - 要导出的密钥长度。

PBEKeySpecspec = new PBEKeySpec(password, salt, iterations, bytes * 8);

//SecretKeyFactory此类表示秘密密钥的工厂。

SecretKeyFactoryskf = SecretKeyFactory.getInstance(PBKDF2_ALGORITHM);

//skf.generateSecret(spec)根据提供的密钥规范(密钥材料)生成 SecretKey 对象。

//SecretKey.getEncoded()返回基本编码格式的密钥,如果此密钥不支持编码,则返回 null。返回字节数组

returnskf.generateSecret(spec).getEncoded();

}

/**

*

* @描述:将十六进制字符串转换为字节数组

* @创建人:wyait

* @创建时间:2017年4月24日 上午10:11:15

* @param hex

* @return

*/

privatestatic 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);

}

returnbinary;

}

/**

*

* @描述:将字节数组转换为十六进制字符串

* @创建人:wyait

* @创建时间:2017年4月24日 上午10:11:22

* @param array

* @return

*/

privatestatic String toHex(byte[] array) {

BigIntegerbi = new BigInteger(1, array);

Stringhex = bi.toString(16);

intpaddingLength = (array.length * 2) - hex.length();

if(paddingLength > 0)

returnString.format("%0" + paddingLength + "d", 0) + hex;

else

returnhex;

}

/**

*

* @描述:main方法测试

* @创建人:wyait

* @创建时间:2017年4月24日 上午10:23:53

* @param args

*/

publicstatic void main(String[] args) {

try{

//Print out 10 hashes

for(int i = 0; i < 10; i++) {

Longs = System.currentTimeMillis();

String salt = HashEncrypt.createSalt();

//System.out.println(HashEncrypt.createHash("p\\r\\nassw0Rd!"));

Longe = System.currentTimeMillis();

System.out.println("生成加盐hash后密钥:第" +i + "次:hashPWd:"

+HashEncrypt.createHash(salt, "12003p\\r\\nassw0Rd!")

+",生成密码所用毫秒值:" + (String.valueOf(e - s)));

}

//Test password validation

booleanfailure = false;

System.out.println("Runningtests...");

for(int i = 0; i < 200; i++) {

Longs = System.currentTimeMillis();

Stringsalt = HashEncrypt.createSalt();

Stringpassword = "" + i;

Stringhash = createHash(salt, password);

Stringsalt1 = HashEncrypt.createSalt();

Longe = System.currentTimeMillis();

System.out.println("password第一次加盐hash:"+ hash + ",生成密码所用毫秒值:"

+(String.valueOf(e - s)));

StringsecondHash = createHash(salt1, password);

System.out.println("password第二次加盐hash:"+ secondHash);

//两个不同盐的hash密码比较

if(hash.equals(secondHash)) {

//System.out.println("FAILURE: TWO HASHES ARE EQUAL!");

System.out.println("password="+ i

+",加盐hash后生成的两个密钥相等!就不可用!");

failure= true;

}

StringwrongPassword = "" + (i + 1);

//使用其他密码是hash比对

if(validatePassword(salt1, wrongPassword, hash)) {

//System.out.println("FAILURE: WRONG PASSWORD ACCEPTED!");

System.out.println("hash="+ hash + ",wrongPassword="

+wrongPassword + ",校验密钥匹配!就不可用!");

failure= true;

}

//用salt+password和使用它们生成的hash比对是否相等

if(!validatePassword(salt, password, hash)) {

System.out.println("FAILURE:GOOD PASSWORD NOT ACCEPTED!");

System.out.println("hash="+ hash + ",password=" + password

+",校验密钥不匹配,hash就是password生成的!就不可用!");

failure= true;

}

}

if(failure)

System.out.println("TESTSFAILED!");

else

System.out.println("TESTSPASSED!");

}catch (Exception ex) {

System.out.println("ERROR:" + ex);

}

}

}

时间: 2024-10-08 09:04:28

如何安全的存储用户密码?(下)代码实现pbkdf2算法加密的相关文章

存储用户密码和数据

来自:https://blog.csdn.net/u012491783/article/details/79465559 密码阶段: 1.单向hash(MD5) 以MD5和sha算法为代表,这类做法比明文直接存储看起来要安全,但是如果在db被攻破的时候,以目前计算机的算力加之黑客的各种技术手段,其实跟明文是差别不大的,我们知道密码学里面破解密码最笨的一种方法是暴力破解,随着目前计算机硬件的发展,带来计算能力的提升,每秒钟上亿次的hash计算已经不是问题,直接暴力破解几乎是分秒的事情,另外与之相近

如何安全的存储用户密码?

原文链接:请猛击 本文我只截取了一小部分知识,请看原文. 一:基础知识:加盐哈希( Hashing with Salt) 我们已经知道,恶意攻击者使用查询表和彩虹表,破解普通哈希加密有多么快.我们也已经 了解到,使用随机加盐哈希可以解决这个问题.但是,我们使用什么样的盐值,又如何将其 混入密码中? 盐值应该使用加密的安全伪随机数生成器( Cryptographically Secure Pseudo-Random Number Generator,CSPRNG )产生.CSPRNG和普通的伪随机

用户密码加密存储十问十答,一文说透密码安全存储

我们数据库的权限管理十分严格,敏感信息开发工程师都看不到,密码明文存储不行吗? 不行.存储在数据库的数据面临很多威胁,有应用程序层面.数据库层面的.操作系统层面的.机房层面的.员工层面的,想做到百分百不被黑客窃取,非常困难. 如果密码是加密之后再存储,那么即便被拖库,黑客也难以获取用户的明文密码.可以说,密码加密存储是用户账户系统的底裤,它的重要性,相当于你独自出远门时缝在内衣里钱,虽然你用到他们的概率不大,但关键时刻他们能救命. 那用加密算法比如AES,把密码加密下再存,需要明文的时候我再解密

如何安全的存储用户的密码

大多数的web开发者都会遇到设计用户账号系统的需求.账号系统最重要的一个方面就是如何保护用户的密码.一些大公司的用户数据库泄露事件也时有发生,所以我们必须采取一些措施来保护用户的密码,即使网站被攻破的情况下也不会造成较大的危害.如果你还在存储用户密码的MD5,那可真的有点弱了.赶紧来看看这篇文章吧. 保护密码最好的的方式就是使用带盐的密码hash(salted password hashing).对密码进行hash操作是一件很简单的事情,但是很多人都犯了错.接下来我希望可以详细的阐述如何恰当的对

从12306帐号泄漏谈用户密码安全

新闻回顾 12月25日圣诞节,据漏洞反馈平台乌云网显示,大量12306用户数据在互联网疯传.本次泄露的用户数据包括用户帐号.明文密码.身份证.邮箱等. 随后,12306官方发表公告,称经过认真核查,此泄露信息全部含有用户的明文密码.12306网站数据库所有用户密码均为非明文转换码,网上泄露的用户信息系经其他网站或渠道流出. 12月26日,中国铁路官方微博发消息,铁路公安机关将涉嫌窃取并泄露12306网站电子信息的两名犯罪嫌疑人抓获,并指出此次用户信息泄漏事件是犯罪嫌疑人"撞库"来完成信

疑似网易泄露用户密码事件浅析

事件概述 2015年10月19日下午,乌云漏洞报告平台宣布接到一起惊人的数据泄密报告,网易的用户数据库疑似泄露,影响到网易163/126邮箱过亿数据,泄露信息包括用户名.密码MD5值.密码密保信息MD5值.登陆IP地址以及用户生日等,解开后测试大部分邮箱依旧还可登陆. 乌云建议用户登陆reg.163.com用户中心,在风险提示处查询近一个月的异常登录记录,以及异地登陆提醒邮件.如有异常,需尽快修改密码,改密码的同时也将密码提示答案进行更新修改,同时开启邮箱的安全防护功能. 另外,对于已被破解的网

Python开发之用户密码存储

在各种线上应用中,用户名密码是用户身份认证的关键,它的重要性不言而喻.一方面,作为保护用户敏感数据的钥匙来说,一旦被破解,系统将敞开大门完全不设防.另一方面,密码这把钥匙本身就是非常敏感的数据:大多数用户会在不同应用中使用近似甚至完全相同的密码.一旦某一个应用的密码被破解,很可能坏人就此掌握了用户的“万能钥匙”,这个用户的其它应用也相当危险了. 这篇博文就重点讨论对于密码本身的存储的安全性考虑,而系统自身的安全性不在此文的范围之内. 对于如此重要的用户密码,究竟该怎样在系统中存储呢? “君子不立

一次有趣的Linux下.Net Core与C语言的合作开发体验:生成Linux标准的用户密码串

最近在项目进程中遇上了Linux用户验证的问题,想着怎么样通过Linux本地用户进行安全校验,于是去查了些资料. Linux的密码存储 查阅资料后发现早期的Linux存储在/etc/password文件中,因为/etc/password权限控制较弱,现在已经不使用了,所以我们这里就不讨论这个文件了,较新的Linux发行版,密码都是存储在/etc/shadow文件中,因为/etc/shadow是管理员权限访问,安全性高出许多,我们可以使用命令来查看文件: $ sudo cat /etc/shado

Windows系统下设置mysql的根用户密码及添加新用户的操作

本篇文章主要是学习mysql的根用户密码的设置,以及如何添加新用户等.详细操作步骤如下. 一.设置根用户密码 1. 安装好PHP及相关软件之后,点开"运行",输入"cmd",打开管理员控制台,如图1所示: 图1 2. 在控制台中,移动到mysql\bin目录下.这个和您安装的php软件有关.我安装的是XAMPP集成软件,mysql\bin的路径如图2所示: 图2 因此,我需要在控制台中输入如下字符串:"cd C:\xampp\mysql\bin"