加入收藏 | 设为首页 | 会员中心 | 我要投稿 开发网_新乡站长网 (https://www.0373zz.com/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 站长学院 > PHP教程 > 正文

php 编码安全,安全从我做起--PHP安全编码

发布时间:2022-12-02 10:57:19 所属栏目:PHP教程 来源:
导读:  当我们的代码越写越多,服务越来越多的用户,产生的影响越来越大时,安全就显得越来越重要了。

  安全的编码习惯,也不是一朝一夕就可以形成的,需要我们在长期的编程过程中养成良好的习惯,本文就WEB攻击
  当我们的代码越写越多,服务越来越多的用户,产生的影响越来越大时,安全就显得越来越重要了。
 
  安全的编码习惯,也不是一朝一夕就可以形成的,需要我们在长期的编程过程中养成良好的习惯,本文就WEB攻击方式中最常见的非法用户输入、SQL注入、XSS跨站攻击做了详细的分析。
 
  1. 验证过滤用户的输入
 
  即使是最普通的字母数字输入也可能是危险的,列举几个容易引起安全问题的字符:
 
  ! $ ^ & * ( ) ~ [ ] \ | { } ' ' ; < > ? - `
 
  在数据库中可能有特殊意义的字符:
 
  ' ' ; \
 
  还有一些非打印字符:
 
  字符\x00或者说ASCII 0,NULL或FALSE
 
  字符\x10和\x13,或者说ASCII 10和13,\n \r
 
  字符\x1a或者说ASCII 26,表示文件的结束
 
  输入错误的参数类型,也可能导致程序出现意想不到的错误。
 
  输入过多的参数值,可能导致溢出等错误。
 
  1.1 PHP中验证用户的输入
 
  这里特别要注意php.ini中的register_globals的设定,在早期的php版本中是默认开启的,这会导致很严重的安全问题:
 
  更安全的代码应该给$admin赋默认FALSE值:上面这段代码看起来是安全的,但是如果register_globals开启了的话,在访问的url中加入?admin=1即可绕过前半部分的逻辑判断。
 
  但是随着越来越多的安全问题,从php 4.2.0开始,register_globals变为了默认关闭。早期人们开发调试的时候发现使用register_globals有极大的便利,所以早期的php版本中默认开启。
 
  当你发现register_globals是on的时候,你可能会在脚本当中加入如下代码使其关闭:
 
  1
 
  ini_set('register_globals', 0);
 
  但实际上,当所有的全局变量已经创建了之后,以上代码并不会起到作用。
 
  但是你可以在文档的根目录下的.htaccess的文件中加上下面这一行:
 
  php_flag register_globals 0
 
  变量声明:强烈建议总是事先声明变量。
 
  检查输入的类型,长度和格式:
 
  字符串检查:在PHP中,字符串几乎可以是任何事情,但有些值并不是严格的字符串类型,可以用is_string()函数来确定。
 
  有些时候你不介意数字作为字符串,可以用empty()函数。
 
  数字类型检查:使用is_int()函数或者is_integer()或is_long(),例如:
 
  也可以使用gettype()函数判断类型后做处理:
 
  至少还有三种方式可以吧$year变量转变为整数:
 
  下表是对各种类型变量使用各函数判断的结果:如果允许浮点型与零的值,可以使用is_numeric()函数来做判断。 判断一个值是否为布尔型的时候使用is_bool()函数。
 
  检查字符串的长度使用strlen()变量:
 
  概括总结一下PHP中类型,长度,格式等验证:
 
  对于一些可能有害的字符,可以用如下的几种方式进行保护:
 
  使用 \ 对其进行转义。
 
  使用引号把他引起来。
 
  使用%nn的方式编码,如urlencode()函数。
 
  可以尝试在php.ini中开启magic_quotes_gpc,这样对于所有由用户GET、POST、COOKIE中传入的特殊字符都会转义。
 
  也可是使用addslashes()函数,但是开启magic_quotes_gpc所造成的影响可能远超过益处。
 
  addslashes()也只对最常见的四个字符做了转义:单引号、双引号、反斜线、空字符。
 
  同时为了使数据还原,需要使用stripslashes()函数php编码,也可能破坏一些多字节的转义。
 
  推荐使用mysql_real_escape_string()函数,虽然只是用来设计转义插入数据库的数据,但是他能转义更多的字符。
 
  如:NULL、\x00、\n、\r、\、'、'和\x1a。使用用例:
 
  使用mysql_real_escape_string()函数也不是万能的,转义一些并非是要写入mysql的数据库的数据可能不会产生作用或者出现错误。
 
  可以根据自己的实际需要,自己使用str_replace()函数写一个针对特殊字符的转义。
 
  1.2 对于文件的路径与名称的过滤
 
  文件名中不能包含二进制数据,否则可能引起问题。
 
  一些系统允许Unicode多字节编码的文件名,但是尽量避免,应当使用ASCII的字符。
 
  虽然Unix系统几乎可以在文件名设定中使用任何符号,但是应当尽量使用 - 和 _ 避免使用其他字符。
 
  同时需要限定文件名的长度。
 
  php中的文件操作通常使用fopen()函数与file_get_contents()函数。
 
  上面代码的问题在于用户POST输入的scriptname没有做任何过滤,如果用户输入../../../../etc/passwd,则有可能读取到系统的passwd文件。
 
  如果发现 .. 字符串就不执行会不会出现问题呢?如果前面并没有路径限制的话,仍然会出现问题:
 
  使用file协议,当用户输入file:///etc/passwd的时候,会把passwd的内容带入$importedData变量中。
 
  2. 防止SQL注入
 
  2.1 SQL注入是如何产生的:
 
  1、接收一个由用户提交的变量,假设变量为$variety:
 
  1
 
  $variety =$_POST['variety'];
 
  2、接收的变量带入构造一个数据库查询语句:
 
  1
 
  $query ='SELECT * FROM wines WHERE variety='$variety'';
 
  3、把构造好的语句提交给MySQL服务器查询,MySQL返回查询结果。
 
  当由用户输入lagrein' or 1=1#时,产生的结果将会完全不同。
 
  2.2 防止SQL注入的几种方式:
 
  检查用户输入的类型,当用户输入的为数字时可以使用如下方式:
 
  使用is_int()函数(或is_integer()或is_long()函数)
 
  使用gettype()函数
 
  使用intval()函数
 
  使用settype()函数
 
  检查用户输入字符串的长度使用strlen()函数。
 
  检查日期或时间是否是有效的,可以使用strtotime()函数
 
  对于一个已经存在的程序来说,可以写一个通用函数来过滤:
 
  对于一个刚开始写的程序,应当设计的更安全一些,PHP5中,增加了MySQL支持,提供了mysqli扩展:
 
  mysqli扩展提供了所有的查询功能。
 
  mysqli扩展也提供了面向对象的版本:
 
  3. 防止XSS攻击
 
  xss攻击一个常用的方法就是注入HTML元素执行js脚本,php中已经内置了一些防御的函数(如htmlentities或者htmlspecialchars):
 
  3.1 过滤用户提交的URL
 
  如果允许用户输入一个URL用来调用一个图片或者链接,你需要保证他不传入javascript:或者vbscript:或data:等非http协议。
 
  可以使用php的内置函数parse_url()函数来分割URL,然后做判断。
 
  设置允许信任的域:
 
  4. 防止远程执行
 
  远程执行通常是使用了php代码执行如eval()函数,或者是调用了命令执行如exec(),passthru(),proc_open(),shell_exec(),system()或popen()。
 
  注入php代码:
 
  php为开发者提供了非常多的方法可以来调用允许php脚本,我们就需要注意对用户可控的数据进行过滤。
 
  4.1 调用的几种方式:
 
  include()和require()函数,eval()函数,preg_replace()采用e模式调用,编写脚本模板。
 
  如果没有找到的话,他会自己创建一个并把它的名字作为它的值,world也是一样。上面代码将会输出Helloworld,php在解析的时候会检查是否存在一个名为Hello的函数。
 
  上传文件中嵌入php代码:
 
  攻击者可以上传一个看似很普通的图片,PDF等,但是实际上呢?
 
  linux下可以使用如下命令插入php代码进入图片中:
 
  $ echo '' >> locked.gif
 
  把代码插入到了locked.gif图片中。
 
  并且此时用file命令查看文件格式仍为图片:
 
  $ file -i locked.giflocked.gif: image/gif
 
  任何的图像编辑或图像处理的程序包括PHP的getimagesize()函数,都会认为它是一个GIF图像。
 
  但是当你使用cat命令查看图片时,可以看到图片末尾的
 
  当把图片的后缀改为php或者已php的方式解析时,插入的phpinfo()函数便会执行。
 
  4.2 Shell命令执行
 
  PHP提供了一些可以直接执行系统命令的函数,如exec()函数或者 `(反引号)。
 
  PHP的安全模式会提供一些保护,但是也有一些方式可以绕过安全模式:
 
  1、上传一个Perl脚本,或者Python或Ruby等,服务器支持的环境,来执行其他语言的脚本可绕过PHP的安全模式。
 
  2、利用系统的缓冲溢出漏洞,绕过安全模式。
 
  wordcount.php?filename=%2Fdev%2Fnull%20%7C%20cat%20-%20%2Fetc%2Fpasswd用户可以输入如下的URL来攻击读取passwd文件:
 
  字符串拼接之后,将会执行 /usr/bin/wc /dev/null | cat - /etc/passwd这条命令
 
  如果能够不适用命令执行函数与eval()函数,可以在php.ini中禁止:disable_functions = 'eval,phpinfo'
 
  PHP中还有一个preg_replace()函数,可能引起代码执行漏洞。
 
  mixed preg_replace ( mixed $pattern , mixed $replacement , mixed $subject [, int $limit ] )
 
  在 subject 中搜索 pattern 模式的匹配项并替换为 replacement 。如果指定了 limit ,则仅替换 limit 个匹配。
 
  如果省略 limit 或者其值为 -1,则所有的匹配项都会被替换。
 
  特别注意:
 
  /e 修正符使 preg_replace() 将 replacement 参数当作 PHP 代码(在适当的逆向引用替换完之后)。
 
  提示:要确保 replacement 构成一个合法的 PHP 代码字符串,否则 PHP 会在报告在包含 preg_replace() 的行中出现语法解析错误。
 
  当用户输入
 
  h=[p hp]phpinfo()[/php]
 
  经过正则匹配后, replacement 参数变为'test('phpinfo()')',
 
  此时phpinfo仅是被当做一个字符串参数了。
 
  但是当我们提交
 
  h=[p hp]{${phpinfo()}}[/php]
 
  时,phpinfo()就会被执行。
 
  在php中,双引号里面如果包含有变量,php解释器会将其替换为变量解释后的结果;单引号中的变量不会被处理。
 
  注意:双引号中的函数不会被执行和替换。
 
  在这里我们需要通过{${}}构造出了一个特殊的变量,'test('{${phpinfo()}}')',达到让函数被执行的效果 ${phpinfo()} 会被解释执行。
 

(编辑:开发网_新乡站长网)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!