Home | 简体中文 | 繁体中文 | 杂文 | Github | 知乎专栏 | Facebook | Linkedin | Youtube | 打赏(Donations) | About
知乎专栏

12.32. 信息安全

SQL注入,OS命令注入,缓冲溢出、跨站脚本、缺少验证、缺少认证、使用硬编码证书、敏感数据忘记加密、不受限制上传文件类型、依赖不可信的输入、用不必要的高级权限执行任务、跨站请求伪造....

12.32.1. CSRF(Cross-site request forgery)跨站请求伪造

CSRF(Cross-site request forgery),中文名称:跨站请求伪造,也被称为:one click attack/session riding,缩写为:CSRF/XSRF

12.32.2. Session 撰改演示

这是一个计数器的例子

		
<?php
session_start();

if(isset($_SESSION['count'])){
	$_SESSION['count']++;
}else{
	$_SESSION['count'] = 1;
}
print($_SESSION['count']);
		
		

首先在IE浏览器上访问该文件,查看目前计数器数值。

现在开始演示如果更改用户的Session数据

通过Firebug等工具,查看PHPSESSID的值,例如我的是 75ff0dd6a0824a2b607777b58c27f78a

cat /tmp/sess_75ff0dd6a0824a2b607777b58c27f78a
count|i:100;
		

将 count|i:100; 改为 count|i:1000; 再次去浏览器刷新看看现在计数器的数值是多少。

通过这种方法可以实现,提升权限,绕过登录等等。

由于session 存储在 tmp 目录下,一旦网站被注入就来带安全隐患

12.32.3. 用户注册与登录安全

用户注册与登录除了使用图片验证外,还应该记录来源IP,同时限制用户使用自动注册工具

12.32.4. 目录文件与权限

12.32.4.1. 读写权限

Apache进程所有者: nobody

程序所有者: www

apache 可以读取程序并运行,但apache 无法改写代码,/tmp等特殊目录可以写入操作

重置权限命令

chown www:www -R /www
chown nobody:nobody -R /www/www.example.com/tmp

find /www/ -type d -exec chmod 755 {} \;
find /www/ -type f -exec chmod 644 {} \;
chmod 744 -R /www/www.example.com/tmp
				

12.32.4.2. 访问权限

屏蔽访问权限

				
<Directory>
<DirectoryMatch>
<Files>
<FilesMatch>
<Location>
<LocationMatch>
			
			

并不是所有目录和文件都需要提供给用户的,例如早期PHP项目中没有使用框架,常常有include, config等等目录需要屏蔽

例 12.3. Example for ECSHOP

				
<VirtualHost *:80>
    ServerAdmin webmaster@example.com
    DocumentRoot /www/www.example.com/
    ServerName www.example.com
    ServerAlias example.com
    DirectoryIndex index.html index.php
    CustomLog "|/srv/httpd/bin/rotatelogs /www/logs/www.example.com/access.%Y-%m-%d.log 86400 480" combined

    <Location /data/>
	    Order allow,deny
	    Deny from all
    </Location>
    <Location /images/upload/>
            Order allow,deny
            Deny from all
    </Location>
    <Location /temp/>
            Order allow,deny
            Deny from all
    </Location>
    <Location /includes/>
            Order allow,deny
            Deny from all
    </Location>
    <Location /library/>
            Order allow,deny
            Deny from all
    </Location>
    <Location /plugin/>
            Order allow,deny
            Deny from all
    </Location>

    <Directory /www/www.example.com/images/>
        <Files *.php>
            Order allow,deny
            Deny from all
        </Files>
    </Directory>
    <Directory /www/www.example.com/js/>
        <Files *.php>
            Order allow,deny
            Deny from all
        </Files>
    </Directory>

    <Directory /www/www.example.com/themes/>
        <Files *.php>
	    Order allow,deny
	    Deny from all
        </Files>
    </Directory>

</VirtualHost>
               
				

12.32.5. 密码安全

虽然md5摘要算法作为密码仍不能保证安全。我一般采用加入干扰词的方法避免被猜中

password = md5/sha1(password + salt)

12.32.6. 注入检查

我们需要在框架的URL(PATHINFO)对象中加入检查功能

/news/%d.html		只能匹配数字ID /news/123.html 合法,如果/news/abc.html 非法
/login/%s.html 		只能匹配字符串	/login/neo.html
/product/[0-9/a-z].html		可以配置数字已经字符
		

post 数据还有上传文件也做同样检查

这里仅仅给你一个思路,实现起来也并不难

12.32.7. 防止恶意刷新与重复提交

在开发中会经常会遇到这样的需求,例如投票模块,要防止恶意刷票,下面来介绍几种解决方按:

1、来源IP / MAC地址限制
      这个是使用最多也是最广泛的方式,通过获取访问用户的来源IP地址,来限制在一段时间内所能使用的票数。
经常用电脑的老手是很容易绕出这种限制的。PPP/PPPoE拨号用户,可以通过断线重拨来更换IP地址;
 		每个网络位置会有一个全球唯一的MAC位址。所以我们也可以根据MAC地址限制用户访问

2、Cookies / Session验证
      这种方式用的也比较多,清除浏览器Cookies,就可以很容易的绕过这种限制了
	  关闭浏览器,Session就会被销毁;客户端禁用Cookie,Session也会失效;

4、验证码,包括图像,语音,电话,邮件以及回答问题
	首先说图片验证码,有些变态的网站,大家可以看到用户的注册、登录、回复、发帖等等,都会使用验证码,但是这种方式会让用户有时感觉很恶心,随着OCR(Optical Character Recognition,光学字符识别)技术的成熟,图片验证码已经不再安全,识别率可能达到90%以上甚至100%
	语音有播放方式和电话方式,听喇叭中读取字符,然后输入验证码。不要以为这是最安全的,语音是一种波形,通过DSP(Digital Signal Processing,数字信号处理)技术很容易识别
	手机短信与电子邮件,不多说了

	回答问题
	如果没有足够海量的题库,很快问题的内容和答案就会被收集。反而让正常投票的用户,觉得投票很恶心、麻烦,产生厌恶心理。渐渐的也被我们抛弃了。


5、注册用户可能投票模块
	游客不能参与,必须注册了账户才能进行投票,并且限制新注册用户,在一段时间内不能参与投票。

6、随机投票地址
	让每一个访问页面的用户得到一个随机唯一的KEY可能通过UUID/GUID生成,通过这个KEY,生成一个投票地址,该地址只能访问一次,使用过后便作废。

总结:很快就会有新的应对方式。我们只能通过上面几种方案的组合方式,增加用户刷新难度,让用户在无法在短期内实现应对方案,你没想出一种新方式。

		

12.32.8. 屏蔽出错信息

12.32.8.1. 屏蔽php出错信息

			
; Error handling and logging ;
; 出错控制和登记 ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; 错误报告是按位的。或者将数字加起来得到想要的错误报告等级。
; E_ALL - 所有的错误和警告
; E_ERROR - 致命性运行时错
; E_WARNING - 运行时警告(非致命性错)
; E_PARSE - 编译时解析错误
; E_NOTICE - 运行时提醒(这些经常是是你的代码的bug引起的,
;也可能是有意的行为造成的。(如:基于未初始化的变量自动初始化为一个
;空字符串的事实而使用一个未初始化的变量)

; E_CORE_ERROR - 发生于PHP启动时初始化过程中的致命错误
; E_CORE_WARNING - 发生于PHP启动时初始化过程中的警告(非致命性错)
; E_COMPILE_ERROR - 编译时致命性错
; E_COMPILE_WARNING - 编译时警告(非致命性错)
; E_USER_ERROR - 用户产生的出错消息
; E_USER_WARNING - 用户产生的警告消息
; E_USER_NOTICE - 用户产生的提醒消息
; 例子:
; error_reporting = E_ALL & ~E_NOTICE ; 显示所有的错误,除了提醒
; error_reporting = E_COMPILE_ERROR|E_ERROR|E_CORE_ERROR ; 仅显示错误
error_reporting = E_ALL & ~E_NOTICE ; 显示所有的错误,除了提醒
display_errors = On ; 显示出错误信息(作为输出的一部分)
; 在最终发布的web站点上,强烈建议你关掉这个特性,并使用
; 错误日志代替(参看下面)。
; 在最终发布的web站点继续让 display_errors 有效可能
; 暴露一些有关安全的信息,例如你的web服务上的文件路径、
; 你的数据库规划或别的信息。
display_startup_errors = Off ; 甚至当display_erroes打开了,发生于PHP的启动的步骤中
; 的错误也不会被显示。
; 强烈建议保持使 display_startup_errors 关闭,
; 除了在改错过程中。
log_errors = Off ; 在日志文件里记录错误(服务器指定的日志,stderr标准错误输出,或error_log(下面的))
; 正如上面说明的那样,强烈建议你在最终发布的web站点以日志记录错误
; 取代直接错误输出。

track_errors = Off ; 保存最近一个 错误/警告 消息于变量 $php_errormsg (boolean)
;error_prepend_string = "<font color=ff0000>;" ; 于错误信息前输出的字符串
;error_append_string = "</font>;" ; 于错误信息后输出的字符串
;error_log = filename ; 记录错误日志于指定文件
;error_log = syslog ; 记录错误日志于系统日志 syslog (NT 下的事件日志, Windows 95下无效)
warn_plus_overloading = Off ; 当将‘+’用于字符串时警告

这项去掉
; E_WARNING - 运行时警告(非致命性错)