我们经常会利用PHP和MYSQ数据库配合开发应用,这其中会涉及到一些常见的应用安全问题,是我们不可以忽视的,以下会逐一列出可能存在的安全问题及解决方法。
1. 设置HTTP认证
对于应用中的某些页面,是不能够直接面向用户开放的,比如一个应用中设定了用户不能够随意删除数据库中的内容,那么这个删除数据库内容的页面就需要做一些加密操作。
说到对一个页面加密,这里有三种有效的方法
- 区分管理员和普通用户,在需加密页面最前面加一个对当前用户身份的判断,区别显示不同的内容。
- 设置HTTP认证,浏览器显示一个弹窗用户输入用户名和口令,只有这两项都正确服务器才能向浏览器发送所请求的HTML页面。
第二种方法可以比较快速实现页面加密,我们这里着重讨论第二种方法,即HTTP认证。
HTTP认证与首部密切相关,我们可以通过php控制服务器向浏览器发送两个关键首部。这涉及到两个重要的首部,header('HTTP/1.1 401 Unauthorized')
向浏览器发送一个禁止访问页面的首部,让浏览器知道用户没有得到查看页面的授权。header('WWW-Authenticate:Basic realm="WDL"')
这个首部要求浏览器尝试提示用户输入一个用户名和口令进行认证。其中有一个值得注意的小地方,就是realm="****"
***是你要填写的基本域,它定义了一个特定用户和口令所保护的安全区。一旦成功地输入了对应一个给定域的用户名和口令,浏览器会记住这个用户名和口令,而对同一个域中后续的认证首部不会再显示验证窗口。换句话说,基本域使得浏览器可以记住你已满足一组给定页面的安全需求,只需为这些页面的认证首部指定相同的基本域。
向浏览器发送了这两个首部之后,就需要php及时接收到用户的输入并做验证。php两个超级全局变量帮了大忙,分别是$_SERVER['PHP_AUTH_USER']
和$_SERVER['PHP_AUTH_PW']
,分别用来接收用户输入的用户名和口令。当然这里你也可以只设置对用户名或者口令的加密,这时候只需要输入一个,然后在php的验证逻辑中只对一个做验证即可。
接下来我给了一个phpHTTP认证验证范本
尽管exit()
函数再在php代码中紧挨两个header()
函数调用下面,但是只有当用户点击了取消按钮才会调用这个函数。如果认证失败,服务器在调用两个header()
函数后不会继续执行。相反,它会重新发送首部,并再次尝试。
2. 防止SQL注入
SQL注入是指用户通过表单输入的数据来破环正常的sql语句结构,伪装成新的sql语句,对数据库数据造成破坏。
这里有几种方式可以防止sql注入:
- 加入表单验证,对输入的数据传到后台前先对其进行验证。
- 后台数据采集处理,对传到后台的数据进行去空格处理以及对特殊字符(如, ’ " 等)进行转义。
- 尽量合理地设计数据库即数据库表,使得设计更合理,减少通过sql注入破坏数据库的机会
表单验证
-
非空验证
可以通过给input标签加上required属性<input type='text' required>
(ie8不支持该属性)。
利用js对每个表单域进行非空验证。 -
数据类型验证
使用isNAN()
函数验证内容是否为数字或者数字格式的字符串,若果是数字,则返回false,否则返回true。(该函数在参数为空字符串或者只包含空格的情况下失效,可以配合parseInt()
函数使用)
后台数据采集处理
-
去两端空格处理
调用trim()
函数可以很方便地去除内容头尾两边地空格,制表符,换行符,回车符等。 -
对特殊字符进行转义
调用mysqli_real_escape_string()
函数对逗号,反斜杆等符号进行转义。 -
非空验证
调用empty()
函数对变量进行非空验证,当一个变量不存在时也默认为空。 -
是否为数字格式
调用is_numeric()
函数验证数据是否为数字或数字格式的字符串。
合理设计数据库和数据库表的结构
SQL DEFAULT命令指定相应列的默认值是一个很好的设计,把该列数据隐藏,防止用户直接通过表单输入干预该列数据,可以有效防止SQL注入对该列数据的破坏。
3. 人类仲裁
要分析一个信息是否被允许或者是否合法,很难脱离人的参与。这里讨论的就是仲裁,在公众看到内容前,要由相关负责人审核并批准这个内容发布到应用上。
我们可以在数据库表建立一列是否批准的列和一个只供负责人审批数据的页面来,实现先将用户提交的数据存入数据库后由负责人审批才能发布的功能。