2023年7月31日发(作者:)

Web安全:细说后端密码安全防范上⼀次笔者写了⼀篇关于安全的⽂章:【】投⽯问路,效果还不错,深受⿎舞。其实和web相关的安全问题不仅于此,⼤致有【XSS攻击】、【前端CSRF攻击】、【前端cookies问题】、【前端点击劫持问题】、【HTTP传输安全】、【DOS攻击】、【后端密码安全】、【SQL注⼊】等⼀系列问题,慢慢给⼤家总结出来吧。。。(为什么这么多“前端…”?emmmmmmm,可能是怕攻击频繁,对服务器造成隐患吧。但其实这些前端/后端的防御措施⼀般都要和后端/前端结合起来才能够更有效的运⾏)今天就和各位唠唠“后端密码安全”,简单说说(其实说是没啥说的…),本⽂代码主要适⽤于中⼩型项⽬,如有不当之处,还请之处嘞。密码安全两三事现在⼀般⼀提起密码安全,就会想到这些年“⼤⽕的”数据库泄露 —— 事实上,这也确实是现在密码安全防范的⼀个重点:泄露渠道:数据库被“偷”服务器被⼊侵通讯被窃听内部⼈员泄露数据撞库有了早些年处于热搜的“CSDN⼏百万⽤户数据泄露”、“京东账号密码数据库泄露”、“12306数据库泄露”事件,业界终于认识到数据库的“不太安全性”,以及做出了⼀些基本的防御措施,⽐如:严禁密码明⽂存储(防泄露)单向变换(防泄露)密码本⾝复杂度要求(防猜解)“加盐”(防猜解)后来做了多少努⼒咱暂且不提,但是现在所说密码安全的防御措施,⼤多数⼈应该都下意识想到哈希算法,它有这样⼏个特点:1. 明⽂-密⽂⼀⼀对应2. 雪崩效应:只要有⼀点不对应,则后⾯所有的都不对应3. 密⽂⽆法反推到明⽂哈希算法常见有:MD5、SHA1、SHA256…说到这就会有⼈问了:第三个特点怎么体现?现在有好多这种MD5反推的⽹站耶。。。那是对于简单⼀些的明⽂:⽐如123456之类的。因为他们⽤的是暴⼒破解(建⽴了数据字典 —— 也就是我们常说的“彩虹表”)。可想⽽知,对于⼀些⾮常复杂的密码,⽽且甚⾄于加密了好多次,那破解⼏乎就⽆从谈起了(字典存储是需要空间的,查字典也是要时间的):表达式md5(明⽂)=密⽂md5(md5(明⽂))=密⽂难易程度易易md5(md5(md5(明⽂)))=密⽂md5(sha1(明⽂))=密⽂md5(md5(md5(明⽂+⼀个复杂字符串)))=密⽂md5(sha256(sha1(明⽂)))=密⽂稍难稍难难难md5(sha256(sha1(明⽂)))=密⽂表达式难难易程度经验:⽤⾜够复杂的密码对抗彩虹表,但尽量不要让⽤户“承担”这件事。密码安全实战⽚段这些天恰好笔者写了⼀个类似每⽇新闻的项⽬,如果做⼤的话,这种项⽬的登录注册必须要进⾏签名/加密,否则在评论区可能会有“意想不到的”错误。(前端代码省略,主要来看⼀下后端代码中关于登录密码的⽚段)这⾥笔者⽤的是,前端⽤的node模块——ejs,签名所⽤md5模块:lib⽂件夹下的⽂件://md5的封装const crypto=require('crypto');s={ MD5_SUFFIX:'ao8durq34fb3($&896359lhd8q是奥迪会36412#', md5:function(str){ var obj=Hash('md5'); //以MD5格式签名 (str); return ('hex'); //hex:16进制(输出格式) }};这个⽂件就是对MD5模块的简单封装,MD5_SUFFIX这个变量就是上⽂所说的那个为了增加复杂度⽽在明⽂后加的“⼀个很复杂的字符串”。crypto模块为node中的MD5模块所在模块,有不明⽩的请移步这⾥我们再简化⼀下场景:假如这个项⽬中有个【管理员】,它的账号和密码是固定的——我们可以通过MD5将“(原定)明⽂密码”进⾏签名,然后将签名后的密码字符串添加到数据库对应字段⾥。在⽤户以【管理员】账号登录时,对⽤户输⼊字符串(明⽂)进⾏MD5加密,然后⽐对数据库中字符串,即可。项⽬>md5_:const common=require('./lib/common');var str='123456';var str2=5(str+'ao8durq34fb3($&896359lhd8q是奥迪会36412#'); //或者:str+5_SUFFIX;(str2);总之,str+后⾯的字符串⼀定要跟上⾯common⽂件⾥的属性变量MD5_SUFFIX⼀致。然后就到了最重要的部分了:验证!这⾥需要注意⼀点的是:如果是⽤post提交数据的话,后端⼀定要⽤post接收数据,否则get请求不会被响应,打印出来数据就是undefined了。route>:const express=require('express');const common=require('../lib/common');const mysql=require('mysql');//node连接mysqlvar db=Pool({host:'localhost',user:'root',password:'root',database:'xxx'});s=function(){ var router=() ((req,res,next)=>{ if(!n['admin_id'] && !='/login'){ ct('/admin/login'); }else{ next(); } }); ('/login',(req,res)=>{ ('admin/',{}); }); ('/login',(req,res)=>{ var username=me; var pass=5(rd+5_SUFFIX); //node操作mysql语句 (`SELECT * FROM XXX WHERE USERNAME='${username}'`,(err,data)=>{ if(err){ (500).send('databases error').end(); }else{ if(==0){ (400).send('empty databases').end(); }else{ if(data[0].password==pass){ n['admin_id']=data[0].ID; ct('/admin/'); }else{ (400).send('密码错误').end(); } } } }) }); ('/',(req,res)=>{ ('进⼊⾸页了').end(); }) return router;}这⾥有⼏个⽐较重要的点:1. ——这⾥使⽤的body-parser中间件(在主⽂件中),这个中间件可以让post数据以请求体的形式传到后端2. 第⼋⾏以use起头——use其实是get和post的“合体”,常⽤在不确定请求会以哪种形式发送时使⽤,这⾥⽤use⽽且不明确【监听路由】,意味着:⽆论⾛到哪⾥,都要经过这个路由监听函数3. 如果是get进来(/login)的,说明什么数据都没有携带,就渲染出登录的模板,如果有数据(第⼆次进这个⽹站或者提交数据后)就去判断这个⽂件最后将router暴露了出去 —— 它当然要被引⽤,但这⾥只是登录设置,同样的,在⼀个项⽬中还有其他各种模块…所以我们采⽤“⼆级路由”的设置⽅式:主⽂件://...//1.获取请求数据(oded());(());//、session//3.模板//('/',require('./')()); //其他页⾯('/admin/',require('./route/')());//t——static//...本⽂所说为express中签名模块crypto的应⽤。⽽在另⼀个新兴框架koa中,有⼀个更为便捷的插件:bcryptjs:“加密”时只需调⽤:require("bcryptjs").hashSync('需要加密的变量参数',5) —— 以级别5进⾏加密⽤户输⼊密码后对⽐时只需调⽤:require("bcryptjs").compareSync('提交的密码','数据库查询到的密码')

2023年7月31日发(作者:)

Web安全:细说后端密码安全防范上⼀次笔者写了⼀篇关于安全的⽂章:【】投⽯问路,效果还不错,深受⿎舞。其实和web相关的安全问题不仅于此,⼤致有【XSS攻击】、【前端CSRF攻击】、【前端cookies问题】、【前端点击劫持问题】、【HTTP传输安全】、【DOS攻击】、【后端密码安全】、【SQL注⼊】等⼀系列问题,慢慢给⼤家总结出来吧。。。(为什么这么多“前端…”?emmmmmmm,可能是怕攻击频繁,对服务器造成隐患吧。但其实这些前端/后端的防御措施⼀般都要和后端/前端结合起来才能够更有效的运⾏)今天就和各位唠唠“后端密码安全”,简单说说(其实说是没啥说的…),本⽂代码主要适⽤于中⼩型项⽬,如有不当之处,还请之处嘞。密码安全两三事现在⼀般⼀提起密码安全,就会想到这些年“⼤⽕的”数据库泄露 —— 事实上,这也确实是现在密码安全防范的⼀个重点:泄露渠道:数据库被“偷”服务器被⼊侵通讯被窃听内部⼈员泄露数据撞库有了早些年处于热搜的“CSDN⼏百万⽤户数据泄露”、“京东账号密码数据库泄露”、“12306数据库泄露”事件,业界终于认识到数据库的“不太安全性”,以及做出了⼀些基本的防御措施,⽐如:严禁密码明⽂存储(防泄露)单向变换(防泄露)密码本⾝复杂度要求(防猜解)“加盐”(防猜解)后来做了多少努⼒咱暂且不提,但是现在所说密码安全的防御措施,⼤多数⼈应该都下意识想到哈希算法,它有这样⼏个特点:1. 明⽂-密⽂⼀⼀对应2. 雪崩效应:只要有⼀点不对应,则后⾯所有的都不对应3. 密⽂⽆法反推到明⽂哈希算法常见有:MD5、SHA1、SHA256…说到这就会有⼈问了:第三个特点怎么体现?现在有好多这种MD5反推的⽹站耶。。。那是对于简单⼀些的明⽂:⽐如123456之类的。因为他们⽤的是暴⼒破解(建⽴了数据字典 —— 也就是我们常说的“彩虹表”)。可想⽽知,对于⼀些⾮常复杂的密码,⽽且甚⾄于加密了好多次,那破解⼏乎就⽆从谈起了(字典存储是需要空间的,查字典也是要时间的):表达式md5(明⽂)=密⽂md5(md5(明⽂))=密⽂难易程度易易md5(md5(md5(明⽂)))=密⽂md5(sha1(明⽂))=密⽂md5(md5(md5(明⽂+⼀个复杂字符串)))=密⽂md5(sha256(sha1(明⽂)))=密⽂稍难稍难难难md5(sha256(sha1(明⽂)))=密⽂表达式难难易程度经验:⽤⾜够复杂的密码对抗彩虹表,但尽量不要让⽤户“承担”这件事。密码安全实战⽚段这些天恰好笔者写了⼀个类似每⽇新闻的项⽬,如果做⼤的话,这种项⽬的登录注册必须要进⾏签名/加密,否则在评论区可能会有“意想不到的”错误。(前端代码省略,主要来看⼀下后端代码中关于登录密码的⽚段)这⾥笔者⽤的是,前端⽤的node模块——ejs,签名所⽤md5模块:lib⽂件夹下的⽂件://md5的封装const crypto=require('crypto');s={ MD5_SUFFIX:'ao8durq34fb3($&896359lhd8q是奥迪会36412#', md5:function(str){ var obj=Hash('md5'); //以MD5格式签名 (str); return ('hex'); //hex:16进制(输出格式) }};这个⽂件就是对MD5模块的简单封装,MD5_SUFFIX这个变量就是上⽂所说的那个为了增加复杂度⽽在明⽂后加的“⼀个很复杂的字符串”。crypto模块为node中的MD5模块所在模块,有不明⽩的请移步这⾥我们再简化⼀下场景:假如这个项⽬中有个【管理员】,它的账号和密码是固定的——我们可以通过MD5将“(原定)明⽂密码”进⾏签名,然后将签名后的密码字符串添加到数据库对应字段⾥。在⽤户以【管理员】账号登录时,对⽤户输⼊字符串(明⽂)进⾏MD5加密,然后⽐对数据库中字符串,即可。项⽬>md5_:const common=require('./lib/common');var str='123456';var str2=5(str+'ao8durq34fb3($&896359lhd8q是奥迪会36412#'); //或者:str+5_SUFFIX;(str2);总之,str+后⾯的字符串⼀定要跟上⾯common⽂件⾥的属性变量MD5_SUFFIX⼀致。然后就到了最重要的部分了:验证!这⾥需要注意⼀点的是:如果是⽤post提交数据的话,后端⼀定要⽤post接收数据,否则get请求不会被响应,打印出来数据就是undefined了。route>:const express=require('express');const common=require('../lib/common');const mysql=require('mysql');//node连接mysqlvar db=Pool({host:'localhost',user:'root',password:'root',database:'xxx'});s=function(){ var router=() ((req,res,next)=>{ if(!n['admin_id'] && !='/login'){ ct('/admin/login'); }else{ next(); } }); ('/login',(req,res)=>{ ('admin/',{}); }); ('/login',(req,res)=>{ var username=me; var pass=5(rd+5_SUFFIX); //node操作mysql语句 (`SELECT * FROM XXX WHERE USERNAME='${username}'`,(err,data)=>{ if(err){ (500).send('databases error').end(); }else{ if(==0){ (400).send('empty databases').end(); }else{ if(data[0].password==pass){ n['admin_id']=data[0].ID; ct('/admin/'); }else{ (400).send('密码错误').end(); } } } }) }); ('/',(req,res)=>{ ('进⼊⾸页了').end(); }) return router;}这⾥有⼏个⽐较重要的点:1. ——这⾥使⽤的body-parser中间件(在主⽂件中),这个中间件可以让post数据以请求体的形式传到后端2. 第⼋⾏以use起头——use其实是get和post的“合体”,常⽤在不确定请求会以哪种形式发送时使⽤,这⾥⽤use⽽且不明确【监听路由】,意味着:⽆论⾛到哪⾥,都要经过这个路由监听函数3. 如果是get进来(/login)的,说明什么数据都没有携带,就渲染出登录的模板,如果有数据(第⼆次进这个⽹站或者提交数据后)就去判断这个⽂件最后将router暴露了出去 —— 它当然要被引⽤,但这⾥只是登录设置,同样的,在⼀个项⽬中还有其他各种模块…所以我们采⽤“⼆级路由”的设置⽅式:主⽂件://...//1.获取请求数据(oded());(());//、session//3.模板//('/',require('./')()); //其他页⾯('/admin/',require('./route/')());//t——static//...本⽂所说为express中签名模块crypto的应⽤。⽽在另⼀个新兴框架koa中,有⼀个更为便捷的插件:bcryptjs:“加密”时只需调⽤:require("bcryptjs").hashSync('需要加密的变量参数',5) —— 以级别5进⾏加密⽤户输⼊密码后对⽐时只需调⽤:require("bcryptjs").compareSync('提交的密码','数据库查询到的密码')