不管是从实用性还是从安全性出发,使用MySQL保存网站用户信息,在登录时获取并进行匹配。若信息存在且正确,为用户分配cookie或session,完成认证,若信息不存在或有误,则认证失败。这是最简单的思维,但实现的方法多种多样,我先肤浅地探讨一二。
最简单直接
分析:这种方法根据查询数据库中的用户名与密码,若二者匹配(唯一),则认为信息正确,即认证成功。但这种方法弊端非常明显,在无安全过滤的情况下,WHERE
处存在两个注入点,恶意提交username=admin'or1=1#
或password=abc'or1=1#
等万能密码可以操控SQL语句,实现任意用户登录。
SELECT * FROM users WHERE username = 'admin'or1=1#' and password = 'xxx';
# 在username处已经把后面的密码认证给注释掉了,且整条语句返回真,从而认证成功。
修复加固一
造成SQL注入的核心成因是程序把用户输入的字符串当成代码来执行,使得SQL语句改变了结构,与开发者的预期产生出入。所以一大重要方法是把用户输入的数据绑定为字符串,可以使用PDO处理,也可以使用PHP的addslashes()
处理输入数据,该函数会自动转义特殊符号,如单引号,可以防止传入数据中的单引号拼接在SQL语句中执行时引起各种错误及恶意利用。
分析:上述加固方法能很好地防止大部分注入攻击,但在数据库设置字符有转换时仍会有编码转换漏洞,如从utf8转向gbk时,传入%df%27
,程序先对%27
进行转义,但在后续转码过程中,反斜杠将与%df
组合形成一个字符从而使单引号逃脱,需要额外注意。
修复加固二
进行身份认证时凭借一条SQL语句返回True
或False
来判断登录成功与否并不可靠,即使对传入的参数处理的足够恰当,但这并不是一种安全的方法。
可以把认证过程分为几个步骤,同时通过将密码进行哈希单向加密,添加salt防止彩虹表爆破等方式保护用户信息安全。先附上简单的示例:
分析:把传入的username
和password
分成两部分进行认证,先查询username
是否存在,返回的数据有空或一条。然后提取返回数据中的password
与传入的password
进行比较,若完全相符则通过认证,不相符或username
不存在则无法通过认证。
该方法可以控制只有当传入正确的用户名与密码才能成功认证,用户名处即使使用万能密码也毫无意义,而密码处即使使用万能密码也不会带入数据库进行处理。
修复加固三
很多开发者现在已没必要重复造轮子了,使用最新版的thinkphp,lavarel等框架进行开发,内置的数据库语句处理已做的非常安全。或使用PDO预处理,绑定参数会自动处理数据中的单引号,防止数据恶意执行。
登录认证后的注入
这种攻击首先是通过注册恶意用户名(名称含有单引号及SQL语句),在正常登录后被暂存于session等地方,然后在其它地方调用时直接使用,导致执行其中恶意代码。