当前位置: 首页 > wzjs >正文

大连网站流量优化定制磁力吧ciliba

大连网站流量优化定制,磁力吧ciliba,微信商店小程序制作教程,mac电脑装wordpress目录 大纲 一、前言 1. 加密意义 2. 常见方案 2.1. Hash 算法 2.2. 单向自适应函数 二、PasswordEncoder 三、DelegatingPasswordEncoder 1. DelegatingPasswordEncoder源码 2. PasswordEncoderFactories源码 四、如何使用 PasswordEncoder 五、密码加密实战 六、密…

目录

大纲

一、前言

1. 加密意义

2. 常见方案

2.1. Hash 算法

2.2. 单向自适应函数

二、PasswordEncoder

三、DelegatingPasswordEncoder

1. DelegatingPasswordEncoder源码

2. PasswordEncoderFactories源码

四、如何使用 PasswordEncoder

五、密码加密实战

六、密码自动升级


大纲

  • 密码为什么要加密
  • 常见加密的解决方案
  • PasswordEncoder 详解
  • 优雅使用加密

一、前言

1. 加密意义

2011 年12月21 日,有人在网络上公开了一个包含600万个 CSDN 用户资料的数据库,数据全部为明文储

存,包含用户名、密码以及注册邮箱。事件发生后 CSDN 在微博、官方网站等渠道发出了声明,解释说此数据库

系2009 年备份所用,因不明原因泄漏,已经向警方报案,后又在官网发出了公开道歉信。在接下来的十多天里,

金山、网易、京东、当当、新浪等多家公司被卷入到这次事件中。整个事件中最触目惊心的莫过于 CSDN 把用户

密码明文存储,由于很多用户是多个网站共用一个密码,因此一个网站密码泄漏就会造成很大的安全隐患。由于

有了这么多前车之鉴,我们现在做系统时,密码都要加密处理。

在前面的案例中,凡是涉及密码的地方,我们都采用明文存储,在实际项目中这肯定是不可取的,因为这会

带来极高的安全风险。

在企业级应用中,密码不仅需要加密,还需要加盐,最大程度地保证密码安全。

2. 常见方案

2.1. Hash 算法

最早我们使用类似 SHA-256 、SHA-512 、MD5等这样的单向 Hash 算法。用户注册成功后,保存在数据

库中不再是用户的明文密码,而是经过 SHA-256 加密计算的一个字行串,当用户进行登录时,用户输入的明文密

码用 SHA-256 进行加密,加密完成之后,再和存储在数据库中的密码进行比对,进而确定用户登录信息是否有

效。如果系统遭遇攻击,最多也只是存储在数据库中的密文被泄漏。

这样就绝对安全了吗?由于彩虹表这种攻击方式的存在以及随着计算机硬件的发展,每秒执行数十亿次

HASH计算己经变得轻轻松松,

这意味着即使给密码加密加盐也不再安全。

参考: 彩虹表

2.2. 单向自适应函数<Adaptive One-way Functions>

在Spring Security 中,我们现在是用一种自适应单向函数 (Adaptive One-way Functions)来处理密码问

题,这种自适应单向函数在进行密码匹配时,会有意占用大量系统资源(例如CPU、内存等),这样可以增加恶

意用户攻击系统的难度。在Spring Securiy 中,开发者可以通过 bcrypt、PBKDF2、sCrypt 以及 argon2 来体验

这种自适应单向函数加密。由于自适应单向函数有意占用大量系统资源,因此每个登录认证请求都会大大降低应

用程序的性能,但是 Spring Secuity 不会采取任何措施来提高密码验证速度,因为它正是通过这种方式来

增强系统的安全性。

参考 1:用户密码哈希 · libsodium 中文文档

参考 2:https://github.com/xitu/gold-miner/blob/master/TODO1/password-hashing-pbkdf2-scrypt-bcrypt-and-argon2.md

  • BCryptPasswordEncoder
    BCryptPasswordEncoder 使用 bcrypt 算法对密码进行加密,为了提高密码的安全性,bcrypt算法故意降低运行速度,以增强密码破解的难度。同时 BCryptPasswordEncoder “为自己带盐”开发者不需要额外维护一个“盐” 字段,使用 BCryptPasswordEncoder 加密后的字符串就已经“带盐”了,即使相同的明文每次生成的加密字符串都不相同。
  • Argon2PasswordEncoder
    Argon2PasswordEncoder 使用 Argon2 算法对密码进行加密,Argon2 曾在 Password Hashing Competition 竞赛中获胜。为了解决在定制硬件上密码容易被破解的问题,Argon2也是故意降低运算速度,同时需要大量内存,以确保系统的安全性。
  • Pbkdf2PasswordEncoder
    Pbkdf2PasswordEncoder 使用 PBKDF2 算法对密码进行加密,和前面几种类似,PBKDF2
    算法也是一种故意降低运算速度的算法,当需要 FIPS (Federal Information Processing Standard,美国联邦信息处理标准)认证时,PBKDF2 算法是一个很好的选择。
  • SCryptPasswordEncoder
    SCryptPasswordEncoder 使用scrypt 算法对密码进行加密,和前面的几种类似,serypt 也是一种故意降低运算速度的算法,而且需要大量内存。

二、PasswordEncoder

通过对认证流程源码分析得知,实际密码比较是由PasswordEncoder完成的,因此只需要使用

PasswordEncoder 不同实现就可以实现不同方式加密。

public interface PasswordEncoder {String encode(CharSequence rawPassword);boolean matches(CharSequence rawPassword, String encodedPassword);default boolean upgradeEncoding(String encodedPassword) {return false;}
}
  • encode 用来进行明文加密的
  • matches 用来比较密码的方法
  • upgradeEncoding 用来给密码进行升级的方法

默认提供加密算法如下:

三、DelegatingPasswordEncoder

根据上面 PasswordEncoder的介绍,可能会以为 Spring security 中默认的密码加密方案应该是四种自适应

单向加密函数中的一种,其实不然,在 spring Security 5.0之后,默认的密码加密方案其实是

DelegatingPasswordEncoder。

从名字上来看,DelegatingPaswordEncoder 是一个代理类,而并非一种全新的密码加密方案,

DeleggtinePasswordEncoder 主要用来代理上面介绍的不同的密码加密方案。

为什么采DelegatingPasswordEncoder 而不是某一个具体加密方式作为默认的密码加密方案呢?主要考虑了

如下两方面的因素:

  • 兼容性:使用 DelegatingPasswrordEncoder 可以帮助许多使用旧密码加密方式的系统顺利迁移到 Spring security 中,它允许在同一个系统中同时存在多种不同的密码加密方案。
  • 便捷性:密码存储的最佳方案不可能一直不变,如果使用 DelegatingPasswordEncoder作为默认的密码加密方案,当需要修改加密方案时,只需要修改很小一部分代码就可以实现。

1. DelegatingPasswordEncoder源码

public class DelegatingPasswordEncoder implements PasswordEncoder {....
}
  • encode 用来进行明文加密的
  • matches 用来比较密码的方法
  • upgradeEncoding 用来给密码进行升级的方法

2. PasswordEncoderFactories源码

public static PasswordEncoder createDelegatingPasswordEncoder() {String encodingId = "bcrypt";Map<String, PasswordEncoder> encoders = new HashMap<>();encoders.put(encodingId, new BCryptPasswordEncoder());encoders.put("ldap", new org.springframework.security.crypto.password.LdapShaPasswordEncoder());encoders.put("MD4", new org.springframework.security.crypto.password.Md4PasswordEncoder());encoders.put("MD5", new org.springframework.security.crypto.password.MessageDigestPasswordEncoder("MD5"));encoders.put("noop", org.springframework.security.crypto.password.NoOpPasswordEncoder.getInstance());encoders.put("pbkdf2", new Pbkdf2PasswordEncoder());encoders.put("scrypt", new SCryptPasswordEncoder());encoders.put("SHA-1", new org.springframework.security.crypto.password.MessageDigestPasswordEncoder("SHA-1"));encoders.put("SHA-256",new org.springframework.security.crypto.password.MessageDigestPasswordEncoder("SHA-256"));encoders.put("sha256", new org.springframework.security.crypto.password.StandardPasswordEncoder());encoders.put("argon2", new Argon2PasswordEncoder());return new DelegatingPasswordEncoder(encodingId, encoders);}

四、如何使用 PasswordEncoder

  • 查看WebSecurityConfigurerAdapter类中源码
static class LazyPasswordEncoder implements PasswordEncoder {private ApplicationContext applicationContext;private PasswordEncoder passwordEncoder;LazyPasswordEncoder(ApplicationContext applicationContext) {this.applicationContext = applicationContext;}@Overridepublic String encode(CharSequence rawPassword) {return getPasswordEncoder().encode(rawPassword);}@Overridepublic boolean matches(CharSequence rawPassword, String encodedPassword) {return getPasswordEncoder().matches(rawPassword, encodedPassword);}@Overridepublic boolean upgradeEncoding(String encodedPassword) {return getPasswordEncoder().upgradeEncoding(encodedPassword);}private PasswordEncoder getPasswordEncoder() {if (this.passwordEncoder != null) {return this.passwordEncoder;}PasswordEncoder passwordEncoder = getBeanOrNull(PasswordEncoder.class);if (passwordEncoder == null) {passwordEncoder = PasswordEncoderFactories.createDelegatingPasswordEncoder();}this.passwordEncoder = passwordEncoder;return passwordEncoder;}private <T> T getBeanOrNull(Class<T> type) {try {return this.applicationContext.getBean(type);}catch (NoSuchBeanDefinitionException ex) {return null;}}@Overridepublic String toString() {return getPasswordEncoder().toString();}}

通过源码分析得知如果在工厂中指定了PasswordEncoder,就会使用指定PasswordEncoder,

否则就会使用默认DelegatingPasswordEncoder。

五、密码加密实战

  • 测试生成的密码
 @Test
public void test() {//1.BCryptPasswordEncoderBCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder();System.out.println(bCryptPasswordEncoder.encode("123"));//2.Pbkdf2PasswordEncoderPbkdf2PasswordEncoder pbkdf2PasswordEncoder = new Pbkdf2PasswordEncoder();System.out.println(pbkdf2PasswordEncoder.encode("123"));//3.SCryptPasswordEncoder //需要额外引入依赖SCryptPasswordEncoder sCryptPasswordEncoder = new SCryptPasswordEncoder();System.out.println(sCryptPasswordEncoder.encode("123"));//4.Argon2PasswordEncoder //需要额外引入依赖Argon2PasswordEncoder argon2PasswordEncoder = new Argon2PasswordEncoder();System.out.println(argon2PasswordEncoder.encode("123"));
}
  • 使用固定密码加密方案
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {@Beanpublic PasswordEncoder BcryptPasswordEncoder() {return new BCryptPasswordEncoder();}@Beanpublic UserDetailsService userDetailsService() {InMemoryUserDetailsManager inMemoryUserDetailsManager = new InMemoryUserDetailsManager();inMemoryUserDetailsManager.createUser(User.withUsername("root").password("$2a$10$WGFkRsZC0kzafTKOPcWONeLvNvg2jqd3U09qd5gjJGSHE5b0yoy6a").roles("xxx").build());return inMemoryUserDetailsManager;}
}
  • 使用灵活密码加密方案 推荐
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {@Beanpublic UserDetailsService userDetailsService() {InMemoryUserDetailsManager inMemoryUserDetailsManager = new InMemoryUserDetailsManager();inMemoryUserDetailsManager.createUser(User.withUsername("root").password("{bcrypt}$2a$10$WGFkRsZC0kzafTKOPcWONeLvNvg2jqd3U09qd5gjJGSHE5b0yoy6a").roles("xxx").build());return inMemoryUserDetailsManager;}
}

六、密码自动升级

推荐使用DelegatingPasswordEncoder 的另外一个好处就是自动进行密码加密方案的升级,这个功能在整合一些

老的系统时非常有用。

  • 准备库表
-- 用户表
CREATE TABLE `user`
(`id`                    int(11) NOT NULL AUTO_INCREMENT,`username`              varchar(32)  DEFAULT NULL,`password`              varchar(255) DEFAULT NULL,`enabled`               tinyint(1) DEFAULT NULL,`accountNonExpired`     tinyint(1) DEFAULT NULL,`accountNonLocked`      tinyint(1) DEFAULT NULL,`credentialsNonExpired` tinyint(1) DEFAULT NULL,PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8;
-- 角色表
CREATE TABLE `role`
(`id`      int(11) NOT NULL AUTO_INCREMENT,`name`    varchar(32) DEFAULT NULL,`name_zh` varchar(32) DEFAULT NULL,PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8;
-- 用户角色关系表
CREATE TABLE `user_role`
(`id`  int(11) NOT NULL AUTO_INCREMENT,`uid` int(11) DEFAULT NULL,`rid` int(11) DEFAULT NULL,PRIMARY KEY (`id`),KEY   `uid` (`uid`),KEY   `rid` (`rid`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8;
  • 插入数据
-- 插入用户数据
BEGIN;INSERT INTO `user`VALUES (1, 'root', '{noop}123', 1, 1, 1, 1);INSERT INTO `user`VALUES (2, 'admin', '{noop}123', 1, 1, 1, 1);INSERT INTO `user`VALUES (3, 'blr', '{noop}123', 1, 1, 1, 1);
COMMIT;
-- 插入角色数据
BEGIN;INSERT INTO `role`VALUES (1, 'ROLE_product', '商品管理员');INSERT INTO `role`VALUES (2, 'ROLE_admin', '系统管理员');INSERT INTO `role`VALUES (3, 'ROLE_user', '用户管理员');
COMMIT;
-- 插入用户角色数据
BEGIN;INSERT INTO `user_role`VALUES (1, 1, 1);INSERT INTO `user_role`VALUES (2, 1, 2);INSERT INTO `user_role`VALUES (3, 2, 2);INSERT INTO `user_role`VALUES (4, 3, 3);
COMMIT;
  • 整合 mybatis
<dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>5.1.38</version>
</dependency><dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter</artifactId><version>2.2.0</version>
</dependency><dependency><groupId>com.alibaba</groupId><artifactId>druid</artifactId><version>1.2.8</version>
</dependency>
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/security?characterEncoding=UTF-88&serverTimezone=UTC&useSSL=false
spring.datasource.username=root
spring.datasource.password=root
mybatis.mapper-locations=classpath:/mapper/*.xml
mybatis.type-aliases-package=com.baizhi.entity
logging.level.com.baizhi.dao=debug
  • 编写实体类
public class User implements UserDetails {private Integer id;private String username;private String password;private Boolean enabled;private Boolean accountNonExpired;private Boolean accountNonLocked;private Boolean credentialsNonExpired;private List<Role> roles = new ArrayList<>();@Overridepublic Collection<? extends GrantedAuthority> getAuthorities() {List<SimpleGrantedAuthority> authorities = new ArrayList<>();for (Role role : roles) {authorities.add(new SimpleGrantedAuthority(role.getName()));}return authorities;}@Overridepublic String getPassword() {return password;}public void setPassword(String password) {this.password = password;}@Overridepublic String getUsername() {return username;}public void setUsername(String username) {this.username = username;}@Overridepublic boolean isAccountNonExpired() {return accountNonExpired;}public void setAccountNonExpired(Boolean accountNonExpired) {this.accountNonExpired = accountNonExpired;}@Overridepublic boolean isAccountNonLocked() {return accountNonLocked;}public void setAccountNonLocked(Boolean accountNonLocked) {this.accountNonLocked = accountNonLocked;}@Overridepublic boolean isCredentialsNonExpired() {return credentialsNonExpired;}public void setCredentialsNonExpired(Boolean credentialsNonExpired) {this.credentialsNonExpired = credentialsNonExpired;}@Overridepublic boolean isEnabled() {return enabled;}public void setEnabled(Boolean enabled) {this.enabled = enabled;}public void setRoles(List<Role> roles) {this.roles = roles;}public Integer getId() {return id;}public void setId(Integer id) {this.id = id;}
}
public class Role {private Integer id;private String name;private String nameZh;public Integer getId() {return id;}public void setId(Integer id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}public String getNameZh() {return nameZh;}public void setNameZh(String nameZh) {this.nameZh = nameZh;}
}
  • 创建dao
@Mapper
public interface UserDao {List<Role> getRolesByUid(Integer uid);User loadUserByUsername(String username);Integer updatePassword(@Param("username") String username,@Param("password") String password);
}
  • 编写 mapper
<!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.baizhi.dao.UserDao"><select id="loadUserByUsername" resultType="User">select id,username,password,enabled,accountNonExpired,accountNonLocked,credentialsNonExpiredfrom `user`where username = #{username}</select><select id="getRolesByUid" resultType="Role">select r.id,r.name,r.name_zh nameZhfrom `role` r,`user_role` urwhere r.id = ur.ridand ur.uid = #{uid}</select><update id="updatePassword">update `user` set password=#{password}where username=#{username}</update></mapper>
  • 编写service 实现
@Service
public class MyUserDetailService implements UserDetailsService,UserDetailsPasswordService {private final UserDao userDao;@Autowiredpublic MyUserDetailService(UserDao userDao) {this.userDao = userDao;}@Overridepublic UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {User user = userDao.loadUserByUsername(username);if (ObjectUtils.isEmpty(user)) {throw new RuntimeException("用户不存在!");}user.setRoles(userDao.getRolesByUid(user.getId()));return user;}@Overridepublic UserDetails updatePassword(UserDetails user, String newPassword) {Integer result = userDao.updatePassword(user.getUsername(), newPassword);if (result == 1) {((User) user).setPassword(newPassword);}return user;}
}
  • 配置securityconfig
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {private final MyUserDetailService myUserDetailService;@Autowiredpublic SecurityConfig(MyUserDetailService myUserDetailService) {this.myUserDetailService = myUserDetailService;}@Overrideprotected void configure(AuthenticationManagerBuilder auth) throws Exception {//查询数据库auth.userDetailsService(myUserDetailService);}}
  • 启动项目测试
http://www.dtcms.com/wzjs/364530.html

相关文章:

  • 咸阳专业网站建设seo软件推广
  • 建筑工程网上教育平台常用的seo工具
  • 做网站cookie传值萧山seo
  • 网站建设的市场分析阿拉营销网站
  • 怎样做网站设计免费留电话号码的广告
  • 北京网站开发外包网络营销业务流程
  • 做网站后台开发工资seo优化公司排名
  • wordpress静态nginx规则高端网站优化公司
  • 衡水网站建设服务商网络营销经典成功案例
  • 元气森林的网络营销方式惠州自动seo
  • 数据分析师培训需要多少钱郑州seo优化服务
  • 网站设计主页获客软件排名前十名
  • 公司注册资金一览表唐山seo排名
  • 西安网址开发 网站制作硬件工程师培训机构哪家好
  • 宣威网站建设互联网营销师培训教材
  • 杭州市萧山区建设局网站网络营销包括几个部分
  • 武汉网站快照优化合肥网站优化
  • nas做视频网站如何点击优化神马关键词排名
  • 网站内页百度不收录湖南靠谱seo优化报价
  • 芜湖做网站的公司网站模板下载
  • 电商网站建设外包推广app赚佣金平台有哪些
  • 在哪里有人做网站郑州seo优化顾问阿亮
  • 专门做各种产品测评的网站云南新闻最新消息今天
  • 安康网站建设公司电话游戏推广拉人渠道
  • 新的网络营销方法长沙seo优化推广
  • 网站如何做路由器网站优化靠谱seo
  • 新疆生产建设兵团编办网站什么是互联网推广
  • wordpress插件对话seo是什么部位
  • 滁州网站建设czesou广州官方新闻
  • 营销型网站建设河北网站推广公司