登陆模块,基本上每个网站都会有,看似简单,无非就是验证一下用户名密码,实际上要想做好登陆模块,是需要动动脑子仔细思考一番的。
登陆方式
- 密码登陆
密码登陆是最为常见的一种登陆方式,用户输入账号密码即可登陆,本为以下内容也多是关于此种方式的一些心得。 - 验证码登陆(免密码登陆)
现在越来越多的网站采用手机验证码的方式来实现登陆,比如
CSDN、知乎、百度云等等,优点就是方便,不用去想自己当初设置的密码是什么,缺点就是短信是要钱的,阿里上貌似是4分5,购买短信包量越大越优惠,然后还要防止恶意刷短信验证码的行为,可以在发送短信前加滑块验证码(图片验证码识别在如今已经太容易了)、限制单个手机号在一定时间内发送短信数量(一定要有),以CSDN为例应该是一小时内最多5条 - 社交账号登陆
比如QQ、微信、微博账号登陆,这种的有时候登陆进去后因为目标网站自身的需要而要求用户先绑定手机号或邮箱,所以有时候也没那么的方便。
登陆用户名密码
用户名和密码要在注册时要求符合一定的复杂度,比如用户名长度不能小于8位,密码要包含英文数字下划线之类的,这些用户可能不在意但作为系统的设计者,用户账号的安全我们不能不在意。为了方便,登陆名最好可以是用户名也可以是用户绑定的其他唯一性字段,比如手机号、邮箱,因为很多用户可能起了个用户名回头就忘了,但是手机号永远不会忘。
防止SQL注入
SQL注人攻击是目前web应用网络攻击中最常见的手段之一,回想自己刚进入这个行业时自己写的一些小网站应该都存在这个漏洞…
举一个SQL注入的例子:
我们在前台输入用户名密码,在已知用户名的情况下(非必需),在密码输入框内输入 'or 1=1# ,这时候如果我们后台是用拼接sql的方式实现的查询,如下图所示,#后边的单引号被注释了:
这时候可以看到SQL执行成功并且能够返回用户数据实现登陆,其实不止可以实现登陆,还可以用这种方式实现一些删除数据,清空表等等更具危害性的操作。
那么如何防止SQL注入呢,我这里只提两个方法
1.参数化查询
参数化查询是指在设计与数据库链接并访问时,在需要数值或数据的地方,使用参数来给值。即在使用参数化查询的情况下,数据库服务器不会将参数的内容视为SQL指令的一部分来处理,而是在数据库完成SQL指令的编译后,才套用参数运行,因此就算参数中有恶意的指令,由于已经编译完成,就不会被数据库运行。说白了就是告诉数据库我传给你两个值,账号和密码,仅仅是值(字符串)而已,你不用再拼接成SQL语句进行编译了。
下面以C#查询MYSQL为例:
public DataTable getUserSafe(string username, string password)
{
List<MySqlParameter> parametlist = new List<MySqlParameter>();
parametlist.Add(new MySqlParameter("@username", username));
parametlist.Add(new MySqlParameter("@password", password));
string sql = "select * from userinfo where username='{0}' and password='{1}'";
DataTable dt= DBToolSet.MySqlHelper.GetDataTable(sql, parametlist);
int count = dt.Rows.Count;
return dt;
}
public static DataTable GetDataTable(string SQLString, List<MySqlParameter> Parameters)
{
using (MySqlConnection connection = new MySqlConnection(connectionString))
{
DataSet ds = new DataSet();
try
{
using (MySqlCommand cmd = new MySqlCommand(SQLString, connection))
{
cmd.Parameters.AddRange(Parameters.ToArray());
connection.Open();
MySqlDataAdapter command = new MySqlDataAdapter(cmd);
command.Fill(ds, "ds");
}
}
catch (MySql.Data.MySqlClient.MySqlException ex)
{
throw new Exception(ex.Message);
}
return ds.Tables[0]; ;
}
}
这时候再输入刚才sql注入相同的参数,看到结果返回数量已经是0了
2.参数过滤
参数过滤就是在前后台添加过滤用户名和密码的机制,禁止用户输入并传递敏感符号比如单引号、井号之类的,防SQL注入的正则表达式网上有很多,这里不再赘述。
记住密码功能
记住密码功能本身就是很不安全的,常见的实现方式是把密码或明文或加密后的密文存储在cookie中,待下次登陆时在取出来。这种方式对于一个技术人员来说一个F12就能粘贴出来,加密后的也能利用,再或者,当网站存在XSS漏洞的时候,攻击者向网站注入恶意代码,然后向自己服务器发送用户的cookie,比如:
安全都是相对的,谁也不能保证存在cookie里的内容绝对安全,所以个人对"记住密码功能"的建议是不设置记住密码功能,记住用户名就好了~ O_O
注意我这里讲的是通过前端js编程实现的记住密码功能,跟浏览器自带的记住密码是不同的,下图为浏览器自带记住密码功能,一般不在我们编程人员的考虑范围内
要想禁止浏览器自带记住密码功能,将密码输入框input的type="password"改成type=“text” 就好了,这时输入框会显示明文,然后再加上οnfοcus=“this.type=‘password’” 属性即可。
防止暴力破解密码
所谓的暴力破解密码就是用穷举法破解密码,将密码进行逐个测试直到找出真正的密码,应对措施我这里介绍两个
1.增加破解难度
发送密码验证请求前先进行人机身份验证,比如加个滑块验证码验证(过几天有时间分享一个滑块验证码的程序),增加其破解难度
上图为简书的登陆验证
2.设置账户锁定策略
记录账号登陆错误次数,一段时间内达到一定阈值后锁定账号,强制一段时间后再试,或者直接进行上一条的人机身份验证,验证成功后解除账号锁定
密码传输安全
密码切不可明文传输,很容易被攻击者通过抓包获取到,而且项目如果需要经过等保测评的话这就会成为一个比较严重的问题。
这里介绍两种实现加密传输的方式
1.RSA非对称加密
RSA加密算法是一种非对称加密算法,简单说就是有两个密钥,一个加密密钥,一个解密密钥,(即公钥和私钥)我在前端用加密密钥对账号密码进行加密,在后台对只有自己知道的揭秘密码进行解密,这样即使被人抓包了也没有办法解密获取我的账号密码。
实现方法:
-
获取公钥、私钥
推荐一个在线生成公钥私钥的网站
http://web.chacuo.net/netrsakeypair -
前台加密
var encrypt = new JSEncrypt();
encrypt.setPublicKey(publicKey);//公钥
var na = encrypt.encrypt($('input[type="text"]').val());
var pa = encrypt.encrypt($('input[type="password"]').val());
$.ajax({
type: "POST",
url: "/Account/UserLoginEncrypt",
data: { loginname: na, password: pa },
datatype: "html",
success: function (data) {
console.log(data);
if (data["Ret"] == 200) {
}
},
error: function () {
}
});
- 后台解密
RSACrypt crypt = new RSACrypt(privateKey);//privateKey私钥
string loginname=crypt.Decrypt(loginname);
string password = crypt.Decrypt(password);
需要引用的RSACrypt 类文件
2.https
现在很多的网站都采用了https协议,最大的好处就是保证数据传输过程中的相对安全
实现方式:
阿里云有免费的SSL证书可以申请,小公司或者个人网站不一定要花钱买证书哦
证书购买后需要进行一些配置,把证书加到自己的网站上
今天就写到这吧,有错误之处欢迎指正