首页
关于
Search
1
给你10个市场数据调研报告的免费下载网站!以后竞品数据就从这里找!
135 阅读
2
php接口优化 使用curl_multi_init批量请求
128 阅读
3
2024年备考系统架构设计师
102 阅读
4
《从菜鸟到大师之路 ElasticSearch 篇》
101 阅读
5
PHP 文件I/O
89 阅读
php
thinkphp
laravel
工具
开源
mysql
数据结构
总结
思维逻辑
令人感动的创富故事
读书笔记
前端
vue
js
css
书籍
开源之旅
架构
消息队列
docker
教程
代码片段
redis
服务器
nginx
linux
科普
java
c
ElasticSearch
测试
php进阶
php基础
登录
Search
标签搜索
php函数
php语法
性能优化
安全
错误和异常处理
问题
vue
Composer
Session
缓存
框架
Swoole
api
并发
异步
正则表达式
php-fpm
mysql 索引
开发规范
协程
dafenqi
累计撰写
785
篇文章
累计收到
4
条评论
首页
栏目
php
thinkphp
laravel
工具
开源
mysql
数据结构
总结
思维逻辑
令人感动的创富故事
读书笔记
前端
vue
js
css
书籍
开源之旅
架构
消息队列
docker
教程
代码片段
副业
redis
服务器
nginx
linux
科普
java
c
ElasticSearch
测试
php进阶
php基础
页面
关于
搜索到
559
篇与
的结果
2023-08-04
PHP语法小记(一)
1,花括号“{}”可以像“[]”操作数组一样操作字符串,来获得指定位置的字符。2,PHP标签“<?php ?>”在独立PHP脚本内可以不写结束标签,这是为了避免意外的空格导致输出而报错。可以用注释来标明脚本结束。3,echo是语法结构,不是函数。后面跟多个字符串时用逗号“,”效率更好。4,数组中,1、'1'、true为索引的时候都会强制转换为1。而'01'不会进行转换,会按照字符串处理。5,将一个类的代码写在不同PHP标签内是不合法的,会报语法错误。而函数则没问题。6,session与cookie的区别与关系。session保存在服务器上,cookie保存在客户浏览器上;session保存可以是硬盘上的文件、数据库、memcached,cookie可以保存到硬盘(持久cookie)和内存里(会话cookie);session_id传递方式有两种,一是cookie,二是get方式(可以通过 session.name 配置项来指定保存session_id的变量名称)。7,获得当前时间戳用$_SERVER['REQUEST_TIME']代替time(),可以减少一次函数调用,效率更高。8,检查字符串是否超过某长度可以用isset($str{n})的语法代替strlen()函数,例如:判断$a的长度是否超过5,可以用isset($a{5})来判断。这样效率更高。9,header()函数过后要exit,否则后面代码还会执行。10,大数组用引用传递,减少内存占用,用完就unset()。11,数据库连接在使用的时候才建立,完全用完了记得关闭连接。12,set_time_limit()的局限性。只能限制脚本本身的运行时间,对于外部执行的时间无法控制,例如:system()函数,流操作,数据库查询等。13,abstract和interface的区别:abstract可以有非抽象方法,interface不行;abstract对方法的访问控制可以有protected,而interface必须为public;abstract只能被继承,当然一个类只能继承一个类,而一个类则可以实现多个interface。14,echo,print,print_r,var_dump,var_export的区别:echo,print是语法结构,不是函数,而且只能显示基本类型,不能显示数组和对象,其他都是函数,可以显示数组和对象;echo 可以显示多个变量,用逗号隔开;print_r第二个参数可以决定是输出变量,还是将变量作为返回值;var_dump会打印变量的详细信息,例如长度和类型,而且可以传递多个变量作为参数;var_export返回的是合法PHP代码格式。15,验证邮箱: filter_var($email, FILTER_VALIDATE_EMAIL);16,获取文件扩展名的方法:一,pathinfo($filename),取extension的值。二,end(explode('.',$filename))。17,文件锁定函数flock——的常量参数。共享锁(读取操作)——LOCK_SH独占锁(写入操作)——LOCK_EX释放锁(无论共享还是独占)——LOCK_UN防堵塞——LOCK_NB可以通过fclose()函数释放锁定操作。18,验证字符串是否是合法IP:不用正则,直接用ip2long(),合法则返回数字,不合法则返回false。19,PHP 5.3开始,可以使用__DIR__来获得当前脚本所在目录,不用再realpath(__FILE__)了。
2023年08月04日
14 阅读
0 评论
0 点赞
2023-08-04
php 利用socket发送GET,POST请求
php 利用socket发送GET,POST请求作为php程序员一定会接触http协议,也只有深入了解http协议,编程水平才会更进一步。最近我一直在学习php的关于http的编程,许多东西恍然大悟,受益匪浅。希望分享给大家。本文需要有一定http基础的开发者阅读。今天给大家带来的是如何利用socket发送GET,POST请求。我借用燕十八老师封装好的一个Http类给进行说明。在日常编程中相信很多人和我一样大部分时间是利用浏览器向服务器提出GET,POST请求,那么可否利用其它方式提出GET,POST请求呢?答案必然是肯定的。了解过HTTP协议的人知道,浏览器提交请求的实质是向服务器发送一个请求信息,这个请求信息有请求行,请求头,请求体(非必须)构成。服务器根据请求信息返回一个响应信息。连接断开。HTTP请求的格式如下所示:1 <request-line> 2 <headers> 3 <blank line> 4 [<request-body>]HTTP响应的格式与请求的格式十分相似:<status-line> <headers> <blank line> [<response-body>]我们可以利用HTTP发送请求的原理,可以重新考虑利用socket发送HTTP请求。Socket的英文原义是“孔”或“插座”。通常也称作“套接字”,用于描述IP地址和端口,是一个通信链的句柄,可以用来实现不同虚拟机或不同计算机之间的通信。在Internet上的主机一般运行了多个服务软件,同时提供几种服务。每种服务都打开一个Socket,并绑定到一个端口上,不同的端口对应于不同的服务。如此看来,其实利用socket操作远程文件和读写本地的文件一样容易,把本地文件看成通过硬件传输,远程文件通过网线传输就行了。因而可以将发送请求的考虑成 建立连接->打开socket接口(fsockopen())->写入请求(fwrite())->读出响应(fread()->关闭文件(fclose())。话不多说,直接上代码: <?php interface Proto { // 连接url function conn($url); //发送get查询 function get(); // 发送post查询 function post(); // 关闭连接 function close(); } class Http implements Proto { const CRLF = "\r\n"; protected $errno = -1; protected $errstr = ''; protected $response = ''; protected $url = null; protected $version = 'HTTP/1.1'; protected $fh = null; protected $line = array(); protected $header = array(); protected $body = array(); public function __construct($url) { $this->conn($url); $this->setHeader('Host: ' . $this->url['host']); } // 此方法负责写请求行 protected function setLine($method) { $this->line[0] = $method . ' ' . $this->url['path'] . '?' .$this->url['query'] . ' '. $this->version; } // 此方法负责写头信息 public function setHeader($headerline) { $this->header[] = $headerline; } // 此方法负责写主体信息 protected function setBody($body) { $this->body[] = http_build_query($body); } // 连接url public function conn($url) { $this->url = parse_url($url); // 判断端口 if(!isset($this->url['port'])) { $this->url['port'] = 80; } // 判断query if(!isset($this->url['query'])) { $this->url['query'] = ''; } $this->fh = fsockopen($this->url['host'],$this->url['port'],$this->errno,$this->errstr,3); } //构造get请求的数据 public function get() { $this->setLine('GET'); $this->request(); return $this->response; } // 构造post查询的数据 public function post($body = array()) { $this->setLine('POST'); // 设计content-type $this->setHeader('Content-type: application/x-www-form-urlencoded'); // 设计主体信息,比GET不一样的地方 $this->setBody($body); // 计算content-length $this->setHeader('Content-length: ' . strlen($this->body[0])); $this->request(); return $this->response; } // 真正请求 public function request() { // 把请求行,头信息,实体信息 放在一个数组里,便于拼接 $req = array_merge($this->line,$this->header,array(''),$this->body,array('')); //print_r($req); $req = implode(self::CRLF,$req); //echo $req; exit; fwrite($this->fh,$req); while(!feof($this->fh)) { $this->response .= fread($this->fh,1024); } $this->close(); // 关闭连接 } // 关闭连接 public function close() { fclose($this->fh); } }利用此类发送一个简单的GET请求:<?php //记得引用Http类 $url="http://home.cnblogs.com/u/DeanChopper/"; $http=new Http($url); $response=$http->get(); print_r($response);返回值为信息,可以对响应信息进行进一步处理,得到自己想得到的内容。
2023年08月04日
14 阅读
0 评论
0 点赞
2023-08-04
浅谈php web安全
浅谈php web安全前言首先,不是web安全的专家,所以这不是web安全方面专家级文章,而是学习笔记、细心总结文章,里面有些是我们phper不易发现或者说不重视的东西。所以笔者写下来方便以后查阅。在大公司肯定有专门的web安全测试员,安全方面不是phper考虑的范围。但是作为一个phper对于安全知识是:“知道有这么一回事,编程时自然有所注意”。概要1、php一些安全配置(1)关闭php提示错误功能(2)关闭一些“坏功能”(3)严格配置文件权限。2、严格的数据验证,你的用户不全是“好”人2.1为了确保程序的安全性,健壮性,数据验证应该包括内容。2.2程序员容易漏掉point或者说需要注意的事项3、防注入3.1简单判断是否有注入漏洞以及原理3.2常见的mysql注入语句(1)不用用户名和密码(2)在不输入密码的情况下,利用某用户(3)猜解某用户密码(4)插入数据时提权(5)更新提权和插入提权同理(6)恶意更新和删除(7)union、join等(8)通配符号%、_(9)还有很多猜测表信息的注入sql33防注入的一些方法2.3.1 php可用于防注入的一些函数和注意事项。2.3.2防注入字符优先级。2.3.3防注入代码(1)参数是数字直接用intval()函数(2)对于非文本参数的过滤(3)文本数据防注入代码。(4)当然还有其他与addslashes、mysql_escape_string结合的代码。4、防止xss攻击4.1Xss攻击过程4.2常见xss攻击地方4.3防XSS方法5、CSRF5.1简单说明CSRF原理5.2防范方法6、防盗链7、防拒CC攻击1、php一些安全配置(1)关闭php提示错误功能在php.ini 中把display_errors改成display_errors = OFF或在php文件前加入error_reporting(0)1)使用error_reporting(0);失败的例子:A文件代码:<? error_reporting(0); echo 555 echo 444; ?>错误:Parse error: parse error, expecting `','' or `';'' in E:\webphp\2.php on line 42)使用error_reporting(0);成功的例子:a文件代码:<?php error_reporting(0); include("b.php"); ?>b文件代码:<?php echo 555 echo 444; ?>这是很多phper说用error_reporting(0)不起作用。第一个例子A.php里面有致命错误,导致不能执行,不能执行服务器则不知有这个功能,所以一样报错。第二个例子中a.php成功执行,那么服务器知道有抑制错误功能,所以就算b.php有错误也抑制了。ps:抑制不了mysql错误。(2)关闭一些“坏功能”1)关闭magic quotes功能在php.ini 把magic_quotes_gpc = OFF避免和addslashes等重复转义2)关闭register_globals = Off在php.ini 把register_globals = OFF在register_globals = ON的情况下地址栏目:http:www.phpben.com?bloger=benwin<?php //$bloger = $_GET['bloger'] //因为register_globals = ON 所以这步不用了直接可以用$bloger echo $bloger; ?>这种情况下会导致一些未初始化的变量很容易被修改,这也许是致命的。所以把register_globals = OFF关掉(3)严格配置文件权限。为相应文件夹分配权限,比如包含上传图片的文件不能有执行权限,只能读取2、严格的数据验证,你的用户不全是“好”人。记得笔者和一个朋友在讨论数据验证的时候,他说了一句话:你不要把你用户个个都想得那么坏!但笔者想说的这个问题不该出现在我们开发情景中,我们要做的是严格验证控制数据流,哪怕10000万用户中有一个是坏用户也足以致命,再说好的用户也有时在数据input框无意输入中文的时,他已经不经意变“坏”了。2.1为了确保程序的安全性,健壮性,数据验证应该包括(1) 关键数据是否存在。如删除数据id是否存在(2) 数据类型是否正确。如删除数据id是否是整数(3) 数据长度。如字段是char(10)类型则要strlen判断数据长度(4) 数据是否有危险字符数据验证有些人主张是把功能完成后再慢慢去写安全验证,也有些是边开发边写验证。笔者偏向后者,这两种笔者都试过,然后发现后者写的验证相对健壮些,主要原因是刚开发时想到的安全问题比较齐全,等开发完功能再写时有两个问题,一个phper急于完成指标草草完事,二是确实漏掉某些point。2.2程序员容易漏掉point或者说需要注意的事项:(1) 进库数据一定要安全验证,笔者在广州某家公司参与一个公司内部系统开发的时候,见过直接把$_POST数据传给类函数classFunctionName($_POST),理由竟然是公司内部使用的,不用那么严格。暂且不说逻辑操作与数据操控耦合高低问题,连判断都没判断的操作是致命的。安全验证必须,没任何理由推脱。(2) 数据长度问题,如数据库建表字段char(25),大多phper考虑到是否为空、数据类型是否正确,却忽略字符长度,忽略还好更多是懒于再去判断长度。(这个更多出现在新手当中,笔者曾经也有这样的思想)(3) 以为前端用js判断验证过了,后台不需要判断验证。这也是致命,要知道伪造一个表单就几分钟的事,js判断只是为了减少用户提交次数从而提高用户体验、减少http请求减少服务器压力,在安全情况下不能防“小人”,当然如果合法用户在js验证控制下是完美的,但作为phper我们不能只有js验证而抛弃再一次安全验证。(4) 缺少对表单某些属性比如select、checkbox、radio、button等的验证,这些属性在web页面上开发者已经设置定其值和值域(白名单值),这些属性值在js验证方面一般不会验证,因为合法用户只有选择权没修改权,然后phper就在后端接受数据处理验证数据的时候不会验证这些数据,这是一个惯性思维,安全问题也就有了,小人一个伪表单足矣致命。(5) 表单相应元素name和数据表的字段名一致,如用户表用户名的字段是user_name,然后表单中的用户名输入框也是user_name ,这和暴库没什么区别。(6) 过滤危险字符方面如防注入下面会独立讲解。3、防注入3.1简单判断是否有注入漏洞以及原理。网址:http:www.phpben.com/benwin.php?id=1 运行正常,sql语句如:select * from phpben where id = 1(1) 网址:http:www.phpben.com/ benwin.php?id=1’ sql语句如:select from phpben where id = 1’ 然后运行异常 这能说明benwin.php文件没有对id的值进行“’” 过滤和intval()整形转换,当然想知道有没有对其他字符如“%”,“/”等都可以用类似的方法穷举测试(很多测试软件使用)(2)网址:http:www.phpben.com/ benwin.php?id=1 and 1=1 则sql语句可能是 select * from phpben where id = 1 and 1=1,运行正常且结果和http:www.phpben.com/benwin.php?id=1结果一样,则说明benwin.php可能没有对空格“ ”、和“and”过滤(这里是可能,所以要看下一点)(3)网址:http:www.phpben.com/ benwin.php?id=1 and 1=2则sql语句可能是 select * from phpben where id = 1 and 1=2 如果运行结果异常说明sql语句中“and 1=2”起作用,所以能3个条件都满足都则很确定的benwin.php存在注入漏洞。ps:这里用get方法验证,post也可以,只要把值按上面的输入,可以一一验证。这说明3.2常见的mysql注入语句。(1)不用用户名和密码//正常语句 $sql ="select * from phpben where user_name='admin' and pwd ='123'"; //在用户名框输入’or’=’or’或 ’or 1=’1 然后sql如下 $sql ="select * from phpben where user_name=' 'or'='or'' and pwd ='' "; $sql ="select * from phpben where user_name=' 'or 1='1' and pwd ='' ";这样不用输入密码。话说笔者见到登录框都有尝试的冲动。(2)在不输入密码的情况下,利用某用户。//正常语句 $sql ="select * from phpben where user_name='$username' and pwd ='$pwd'"; //利用的用户名是benwin 则用户名框输入benwin’# 密码有无都可,则$sql变成 $sql ="select * from phpben where user_name=' benwin'#' and pwd ='$pwd'";这是因为mysql中其中的一个注悉是“#”,上面语句中#已经把后面的内容给注悉掉,所以密码可以不输入或任意输入。网上有些人介绍说用“/”来注悉,笔者想提的是只有开始注悉没结束注悉“/”时,mysql会报错,也不是说“/*/”不能注悉,而是这里很难添加上“/”来结束注悉,还有“-- ”也是可以注悉mysql 但要注意“--”后至少有一个空格也就是“-- ”,当然防注入代码要把三种都考虑进来,值得一提的是很多防注入代码中没把“-- ”考虑进防注入范围。(3)猜解某用户密码//正常语句 $sql ="select * from phpben.com where user_name='$username' and pwd ='$pwd'"; //在密码输入框中输入“benwin’ and left(pwd,1)='p'#”,则$sql是 $sql ="select * from phpben.com where user_name=' benwin' and left(pwd,1)='p'#' and pwd ='$pwd'";如果运行正常则密码的密码第一个字符是p,同理猜解剩下字符。(4)插入数据时提权//正常语句,等级为1 $sql = "insert into phpben.com (`user_name`,`pwd`,`level`) values(‘benwin','iampwd',1) "; //通过修改密码字符串把语句变成 $sql = "insert into phpben.com (`user_name`,`pwd`,`level`) values(‘benwin','iampwd',5)#',1) "; $sql = "insert into phpben.com (`user_name`,`pwd`,`level`) values(‘benwin','iampwd',5)-- ',1) ";这样就把一个权限为1的用户提权到等级5(5)更新提权和插入提权同理//正常语句 $sql = "update phpben set `user_name` ='benwin', level=1"; //通过输入用户名值最终得到的$sql $sql = "update phpben set `user_name` ='benwin',level=5#', level=1"; $sql = "update phpben set `user_name` ='benwin',level=5-- ', level=1";(6)恶意更新和删除//正常语句 $sql = "update phpben set `user_name` = ‘benwin' where id =1"; //注入后,恶意代码是“1 or id>0” $sql = "update phpben set `user_name` = ‘benwin' where id =1 or id>0"; //正常语句 $sql = "update phpben set `user_name` =’benwin’ where id=1"; //注入后 $sql = "update phpben set `user_name` ='benwin' where id>0#' where id=1"; $sql = "update phpben set `user_name` ='benwin' where id>0-- ' where id=1";(7)union、join等//正常语句 $sql ="select * from phpben1 where `user_name`=’benwin’ "; //注入后 $sql ="select * from phpben1 where`user_name`=’benwin’ uninon select * from phpben2#’ "; $sql ="select * from phpben1 where`user_name`=’benwin’ left join……#’ ";(8)通配符号%、_//正常语句 $sql ="select * from phpben where `user_name`=’benwin’ "; //注入通配符号%匹配多个字符,而一个_匹配一个字符,如__则匹配两个字符 $sql ="select * from phpben where `user_name` like ’%b’ "; $sql ="select * from phpben where `user_name` like ’_b_’ ";这样只要有一个用户名字是b开头的都能正常运行,“ _b_”是匹配三个字符,且这三个字符中间一个字符时b。这也是为什么有关addslashes()函数介绍时提示注意没有转义%和_(其实这个是很多phper不知问什么要过滤%和_下划线,只是一味的跟着网上代码走)(9)还有很多猜测表信息的注入sql//正常语句 $sql ="select * from phpben1 where`user_name`='benwin'"; //猜表名,运行正常则说明存在phpben2表 $sql ="select * from phpben1 where`user_name`='benwin' and (select count(*) from phpben2 )>0#' "; //猜表字段,运行正常则说明phpben2表中有字段colum1 $sql ="select * from phpben1 where`user_name`='benwin' and (select count(colum1) from phpben2 )>0#'"; //猜字段值 $sql ="select * from phpben1 where`user_name`='benwin' and left(pwd,1)='p'#’'";当然还有很多,笔者也没研究到专业人士那种水平,这里提出这些都是比较常见的,也是phper应该知道并掌握的,而不是一味的在网上复制粘贴一些防注入代码,知然而不解其然。下面一些防注入方法回看可能更容易理解。3.3防注入的一些方法3.3.1 php可用于防注入的一些函数和注意事项。(1)addslashes 和stripslashes。Addslashes给这些 “’”、“””、“\”,“NULL” 添加斜杆“\’”、“\””、“\”,“\NULL”, stripslashes则相反,这里要注意的是php.ini是否开启了magic_quotes_gpc=ON,开启若使用addslashes会出现重复。所以使用的时候要先get_magic_quotes_gpc()检查一般代码类似:if(!get_magic_quotes_gpc()) { $abc = addslashes($abc); }其实这个稍微学习php一下的人都知道了,只不过笔者想系统点介绍(前面都说不是专家级文章),所以也顺便写上了。addslashes(2)mysql_escape_string()和mysql_ real _escape_string()mysql_real_escape_string 必须在(PHP 4 >= 4.3.0, PHP 5)的情况下才能使用。否则只能用mysql_escape_stringif (PHP_VERSION >= '4.3') { $string = mysql_real_escape_string($string); }else { $string = mysql_escape_string($string ); }mysql_escape_string()和mysql_ real _escape_string()却别在于后者会判断当前数据库连接字符集,换句话说在没有连接数据库的前提下会出现类似错误:Warning: mysql_real_escape_string() [function.mysql-real-escape-string]: Access denied for user 'ODBC'@'localhost' (using password: NO) in E:\webphp\test.php on line 11(3)字符代替函数和匹配函数str_replace() 、perg_replace()这些函数之所以也在这里提是因为这些函数可以用于过滤或替代一些敏感、致命的字符。3.3.2防注入字符优先级。防注入则要先知道有哪些注入字符或关键字,常见的mysql注入字符有字符界定符号如“'”、“"”;逻辑关键字如“and”、“or”;mysql注悉字符如“#”,“-- ”,“/*/”;mysql通配符“%”,“_”;mysql关键字“select|insert|update|delete||union|join|into|load_file|outfile”(1)对于一些有规定格式的参数来说,防注入优先级最高的是空格” ”。如一些银行卡号,身份证号,邮箱,电话号码,,生日,邮政编码等这些有自己规定的格式且格式规定不能有空格符号的参数,在过滤的时候一般最先过滤掉空格(包括一些空格“变种”),因为其他字符界定符号,逻辑关键字,mysql注悉,注意下图可以看出重要的是“'”,“ ”ps:空格字符的变种有:“%20”,“\n”,“\r”,“\r\n”,“\n\r”,“chr("32")” 这也是为什么mysql_escape_string()和mysql_real_escape_string() 两个函数转义“\n”,“\r”。其实很多phper只知道转义\n,\r而不知原因,在mysql解析\n,\r时把它们当成空格处理,笔者测试验证过,这里就不贴代码了。(2)“and”,“or”,“\”,“#”,“-- ”逻辑关键可以组合很多注入代码;mysql注悉则把固有sql代码后面的字符全部给注悉掉从而让注入后的sql语句能正常运行;“\”也是能组合很多注入字符\x00,\x1a。ps:sql解析“#”,“-- ”是大多数mysql防注入代码没有考虑到的,也是很多phper忽略。还有因为一些phper给参数赋值的时候会有用“-”来隔开,所以笔者建议不要这样写参数,当然也可以再过滤参数的时候“-- ”(注意有空格的,没空格不解析为注悉)当一个整体过滤而不是过滤“-” ,这样就避免过多过滤参数。(3)“null”,“%”,“_”这几个不能独立,都不要在特定情况下,比如通配字符“%,_”都要在mysql like子句的前提下。所以“%”,“_”的过滤一般在搜索相关才过滤,不能把它们纳入通常过滤队列,因为有些如邮箱就可以有”_”字符(4)关键字“select|insert|update|delete|*|union|join|into|load_file|outfile”也许你会问怎么这些重要关键字却优先级这么低。笔者想说的是因为这些关键字在没有“'”,“"”,“”,“and”,“or”等情况下购不成伤害。换句话说这些关键字不够“独立”,“依赖性”特别大。当然优先级低,不代表不要过滤。3.3.3防注入代码。(1)参数是数字直接用intval()函数注意:现在很多网上流行的防注入代码都只是只是用addslashes()、mysql_escape_string()、mysql_real_escape_string()或三者任意组合过滤,但phper以为过滤了,一不小心一样有漏洞,那就是在参数为数字的时候:$id = addslashes($_POST['id']); //正确是$id = intval($_POST['id']); $sql =" select * from phpben.com where id =$id"; $sql =" select * from phpben.com where id =1 or 1=1";对比容易发现,post过来的数据通过addslashes过滤后的确很多注入已经不起作用,但是$id并没有intval,导致漏洞的存在,这是个小细节,不小心则导致漏洞。(2)对于非文本参数的过滤文本参数是指标题、留言、内容等可能有“’”,“’”等内容,过滤时不可能全部转义或代替。但非文本数据可以。function _str_replace($str ) { $str = str_replace(" ","",$str); $str = str_replace("\n","",$str); $str = str_replace("\r","",$str); $str = str_replace("'","",$str); $str = str_replace('"',"",$str); $str = str_replace("or","",$str); $str = str_replace("and","",$str); $str = str_replace("#","",$str); $str = str_replace("\\","",$str); $str = str_replace("-- ","",$str); $str = str_replace("null","",$str); $str = str_replace("%","",$str); //$str = str_replace("_","",$str); $str = str_replace(">","",$str); $str = str_replace("<","",$str); $str = str_replace("=","",$str); $str = str_replace("char","",$str); $str = str_replace("declare","",$str); $str = str_replace("select","",$str); $str = str_replace("create","",$str); $str = str_replace("delete","",$str); $str = str_replace("insert","",$str); $str = str_replace("execute","",$str); $str = str_replace("update","",$str); $str = str_replace("count","",$str); return $str; }ps:还有一些从列表页操作过来的一般href是”phpben.php?action=delete&id=1”,这时候就注意啦,_str_replace($_GET['action'])会把参数过滤掉,笔者一般不用敏感关键作为参数,比如delete会写成del,update写成edite,只要不影响可读性即可;还有上面代码过滤下划线的笔者注悉掉了,因为有些参数可以使用下划线,自己权衡怎么过滤;有些代码把关键字当重点过滤对象,其实关键字的str_replace很容易“蒙过关”,str_replace(“ininsertsert”)过滤后的字符还是insert,所以关键的是其他字符而不是mysql关键字。(3)文本数据防注入代码。文本参数是指标题、留言、内容等这些数据不可能也用str_replace()过滤掉,这样就导致数据的完整性,这是很不可取的。代码:function no_inject($str) { if(is_array($str)) { foreach($str as $key =>$val) { $str[$key]=no_inject($val); } }else { //把一些敏感关键字的第一个字母代替掉,如or 则用"or"代替 $str = str_replace(" "," ",$str); $str = str_replace("\\","\",$str); $str = str_replace("'"," ' ",$str); $str = str_replace('"'," " ",$str); $str = str_replace("or"," o r",$str); $str = str_replace("and"," and",$str); $str = str_replace("#","# ",$str); $str = str_replace("-- ","-- ",$str); $str = str_replace("null","null",$str); $str = str_replace("%","%",$str); //$str = str_replace("_","_",$str); $str = str_replace(">","͸",$str); $str = str_replace("<",">",$str); $str = str_replace("=","=",$str); $str = str_replace("char","char",$str); $str = str_replace("declare","declare",$str); $str = str_replace("select","select",$str); $str = str_replace("create","create",$str); $str = str_replace("delete","delete",$str); $str = str_replace("insert","insert",$str); $str = str_replace("execute","execute",$str); $str = str_replace("update","update",$str); $str = str_replace("count","count",$str); } return $str; }(4)当然还有其他与addslashes、mysql_escape_string结合的代码。防注入的代码其实来来去去都是那些组合,然后根据自己程序代码变通,笔者这些代码也是没考虑全的,不如cookes、session、request都没全过滤。重要是知道其中原理,为什么过滤这些字符,字符有什么危害。当然还有一些笔者没考虑也没能力考虑到的方面比如还有哪些关键字之类,欢迎mailto:chen_bin_wen@163.com/445235728@qq.com4、防止xss攻击XSS:cross site script 跨站脚本,为什么不叫css,为了不和div+css混淆。4.1Xss攻击过程:(1)发现A站有xss漏洞。(2)注入xss漏洞代码。可以js代码,木马,脚本文件等等,这里假如A站的benwin.php这个文件有漏洞。(3)通过一些方法欺骗A站相关人员运行benwin.php,其中利用相关人员一些会员信息如cookies,权限等。相关人员:管理员(如贴吧版主),管理员一般有一定权限。目的是借用管理员的权限或进行提权,添或加管理员,或添加后门,或上传木马,或进一步渗透等相关操作。A站会员:会员运行A站的benwin.php。目的一般是偷取会员在A站的信息资料。方法:1) 在A站发诱骗相关人到benwin.php的信息,比如网址,这种是本地诱骗2) 在其他网站发诱骗信息或者发邮件等等信息。一般通过伪装网址骗取A站相关人员点击进benwin.php(4)第三步一般已经是一次xss攻击,如果要更进一步攻击,那不断重复执行(2)、(3)步以达到目的。简单例说xss攻击代码:benwin.php文件<html> <head> <title>简单xss攻击例子</title></head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> <dody> <form action="phpben.com?user_name=<?php echo $user_name; ?>"> <input type="submit" value="提交" > </form> </body> </html>当用户名$user_name的值是“benwin" onSubmit="alert('这是xss攻击的例子');" class= "”(这里)<form action="phpben.com?user_name=benwin" onSubmit="alert('这是xss攻击的例子');" class= "" > <input type="submit" value="提交" > </form>当提交表单的时候就会弹出提示框。(1) 很明显$user_name在保存进数据库的时候没有过滤xss字符(和防注入很像,这里举例说明)==>发现漏洞(2) 构造xss代码:benwin" onSubmit="alert('这是xss攻击的例子');" class= "" 传入数据库(3) 骗相关人员进来点击“提交”按钮4.2常见xss攻击地方(1)Js地方<script language="javascript"> var testname =" <?php echo $testname;?>"; </script>$testname的值只要符合js闭合关系:“";alert("test xss ");”(以下同理)(2)form表单里面<input type="text" name="##" value="<?php echo $val; ?>" />(3)a标签<a href="benwin.php?id= <?php echo $id; ?>">a标签可以隐藏xss攻击</a>(4)用得很多的img标签<img src="<?php echo $picPath; ?>" />甚至一些文本中插入整个img标签并且用width、 height、css等隐藏的很隐蔽(5)地址栏目总之,有输出数据的地方,更准确的说是有输出用户提交的数据的地方,都有可能是XSS攻击的地方。4.3防XSS方法防xss方法其实和防注入很相似,都是一些过滤、代替、实体化等方法(1)过滤或移除特殊的Html标签。例如:< 、>、<,、> ’、”、<script>、 <iframe> 、<,、>、"(2)过滤触发JavaScript 事件的标签。例如 onload、onclick、onfocus、onblur、onmouseover等等。(3)php一些相关函数,strip_tags()、htmlspecialchars()、htmlentities()等函数可以起作用5、CSRFCSRF跨站请求伪造cross site request forgery。5.1简单说明CSRF原理(1)A登录Site1(如现在网民常上的淘宝、微博、QQ等),产生一些信息,session、cookies等等,且一直保持没退出。(2)A再登录Site2(如一些成人网等,至于怎么跑到Site2,多数是Site通过些手段,邮件欺骗等),打开site2的浏览器和打开site1的一样,否则无效(3)Site2站中伪造了Site1的http请求(如修改密码,买东西,转账等),Site1的服务器误以为A在site1的正常操作(因为同浏览器且A还没登出),然后就运行了请求,那么csrf已成功操作。csrf和xss很相似。笔者开始也一时混淆,一位热心网友提醒下,修改csrf和xss的区别xss:注重于修改、获取页面元素和值,而且可以执行任意html代码或javascript,能执行代码那肯定能偷取cookies等网站信息csrf:不能修改、获取页面元素和值,而且可以执行任意html代码或javascript,注重利用客户已在安全网站(比如淘宝)登录且产生给非安全网站利用的cookies等信息,然后用户在非安全网站点击连接等一些触发非安全网站向安全网站发送请求。伪造的请求可以很多方面,发邮件、改密码、返回用户信息、交易等等,所以相对与xss攻击来说csrf危害更严重。5.2防范方法。对于phper(1)严密操控执行入口执行一些敏感操作比如改密码这些操作前判断请求来源,只有本站服务器发的请求才可以执行。判断方法可以判断ip来源。非本站服务器ip不会执行。(2)本站有外链的话做些必要操作一般site2的hacker会在site1(比如论坛里)里发欺骗连接,因为在site1诱骗的相关人员一般都登录site1了,满足csrf气体条件之一。如当你点击QQ邮件里面的长外链时候,回跳转到一个页面提示“有风险”之类,这样不仅可以减低跳出率,一些不懂的人看到这样的提示,若不是非必要而是处于好奇点击的连接一般不会继续点击访问;还有是QQ邮件正文里的图片在加载内容时是不加载图片的,要点击“显示图片”按钮才显示图片,这里一个原因之一就是避免攻击。当然对于用户体验来说这是不可取的,可以优化的是判断到一些网址(如QQ本身网址)是安全直接可以显示(不用提示),而可疑的才提示或禁止。(3)防止csrf也可以用防xss的方法。6、防盗链盗链问题增加服务器的负担。盗链就是盗链网站盗取被盗链网站资源来实现一些功能。盗链方面主要是图片、视频、以及其他资源下载文件。方法:判断ip,只有本站服务器才能使用站点资源,否则不能使用。代码:(1)在Apache htaccess添加RewriteEngine on RewriteCond %{HTTP_REFERER} !^$ [NC] RewriteCond %{HTTP_REFERER} !phpben.com [NC] RewriteCond %{HTTP_REFERER} !google.com [NC] RewriteCond %{HTTP_REFERER} !baidu.com [NC] RewriteCond %{HTTP_REFERER} !zhuaxia.com [NC] RewriteRule .(jpg|gif|png|bmp|swf|jpeg) /image/replace.gif [R,NC,L] RewriteRule ^(.*)$ http:\/\/phpben.com\/image\/$1 [L]这样,凡是不是phpben.com google.com baidu.com zhuaxia.com 域名请求的都返回replace.gif代替返回7、防CC攻击CC攻击:是利用不断对网站发送连接请求致使形成拒绝服务的目的。详细百度百科:http://baike.baidu.com/view/662394.htm代码:session_start(); $ll_nowtime = $timestamp ; if (session_is_registered('ll_lasttime')){ $ll_lasttime = $_SESSION['ll_lasttime']; $ll_times = $_SESSION['ll_times'] + 1; $_SESSION['ll_times'] = $ll_times; }else{ $ll_lasttime = $ll_nowtime; $ll_times = 1; $_SESSION['ll_times'] = $ll_times; $_SESSION['ll_lasttime'] = $ll_lasttime; } if (($ll_nowtime - $ll_lasttime)<3){ if ($ll_times>=5){ header(sprintf("Location: %s",'http://127.0.0.1')); exit; } }else{ $ll_times = 0; $_SESSION['ll_lasttime'] = $ll_nowtime; $_SESSION['ll_times'] = $ll_times; }
2023年08月04日
14 阅读
0 评论
0 点赞
2023-08-04
让PHP更快的提供文件下载
让PHP更快的提供文件下载一般来说, 我们可以通过直接让URL指向一个位于Document Root下面的文件, 来引导用户下载文件.但是, 这样做, 就没办法做一些统计, 权限检查, 等等的工作. 于是, 很多时候, 我们采用让PHP来做转发, 为用户提供文件下载.<?php$file = "/tmp/dummy.tar.gz"; header("Content-type: application/octet-stream"); header('Content-Disposition: attachment; filename="' . basename($file) . '"'); header("Content-Length: ". filesize($file)); readfile($file);但是这个有一个问题, 就是如果文件是中文名的话, 有的用户可能下载后的文件名是乱码.于是, 我们做一下修改(参考: :<?php$file = "/tmp/中文名.tar.gz"; $filename = basename($file); header("Content-type: application/octet-stream"); //处理中文文件名 $ua = $_SERVER["HTTP_USER_AGENT"]; $encoded_filename = urlencode($filename); $encoded_filename = str_replace("+", "%20", $encoded_filename); if (preg_match("/MSIE/", $ua)) { header('Content-Disposition: attachment; filename="' . $encoded_filename . '"'); } else if (preg_match("/Firefox/", $ua)) { header("Content-Disposition: attachment; filename*=\"utf8''" . $filename . '"'); } else { header('Content-Disposition: attachment; filename="' . $filename . '"'); } header('Content-Disposition: attachment; filename="' . $filename . '"'); header("Content-Length: ". filesize($file)); readfile($file);恩, 现在看起来好多了, 不过还有一个问题, 那就是readfile, 虽然PHP的readfile尝试实现的尽量高效, 不占用PHP本身的内存, 但是实际上它还是需要采用MMAP(如果支持), 或者是一个固定的buffer去循环读取文件, 直接输出.输出的时候, 如果是Apache + PHP mod, 那么还需要发送到Apache的输出缓冲区. 最后才发送给用户. 而对于Nginx + fpm如果他们分开部署的话, 那还会带来额外的网络IO.那么, 能不能不经过PHP这层, 直接让Webserver直接把文件发送给用户呢?今天, 我看到了一个有意思的文章: How I PHP: X-SendFile.我们可以使用Apache的module mod_xsendfile, 让Apache直接发送这个文件给用户:<?php$file = "/tmp/中文名.tar.gz"; $filename = basename($file); header("Content-type: application/octet-stream"); //处理中文文件名 $ua = $_SERVER["HTTP_USER_AGENT"]; $encoded_filename = urlencode($filename); $encoded_filename = str_replace("+", "%20", $encoded_filename); if (preg_match("/MSIE/", $ua)) { header('Content-Disposition: attachment; filename="' . $encoded_filename . '"'); } else if (preg_match("/Firefox/", $ua)) { header("Content-Disposition: attachment; filename*=\"utf8''" . $filename . '"'); } else { header('Content-Disposition: attachment; filename="' . $filename . '"'); } header('Content-Disposition: attachment; filename="' . basename($file) . '"'); //让Xsendfile发送文件 header("X-Sendfile: $file");X-Sendfile头将被Apache处理, 并且把响应的文件直接发送给Client.Lighttpd和Nginx也有类似的模块, 大家有兴趣的可以去找找看 :)
2023年08月04日
22 阅读
0 评论
0 点赞
2023-08-04
如何设置一个严格30分钟过期的Session
如何设置一个严格30分钟过期的Session我在面试的时候, 经常会问一个问题: "如何设置一个30分钟过期的Session?", 大家不要觉得看似简单, 这里面包含的知识挺多, 特别适合考察基本功是否扎实, 谁来回答试试? 呵呵为什么问这个问题呢? 1. 我在Twitter上看到了有人讨论这个问题, 2 想起来我经常问这个问题, 所以~~在这里, 我来解答下这个题目.第一种回答那么, 最常见的一种回答是: 设置Session的过期时间, 也就是session.gc_maxlifetime, 这种回答是不正确的, 原因如下:首先, 这个PHP是用一定的概率来运行session的gc的, 也就是session.gc_probability和session.gc_divisor(介绍参看 深入理解PHP原理之Session Gc的一个小概率Notice), 这个默认的值分别是1和100, 也就是有1%的机会, PHP会在一个Session启动时, 运行Session gc. 不能保证到30分钟的时候一定会过期.那设置一个大概率的清理机会呢? 还是不妥, 为什么? 因为PHP使用stat Session文件的修改时间来判断是否过期, 如果增大这个概率一来会降低性能, 二来, PHP使用"一个"文件来保存和一个会话相关的Session变量, 假设我5分钟前设置了一个a=1的Session变量, 5分钟后又设置了一个b=2的Seesion变量, 那么这个Session文件的修改时间为添加b时刻的时间, 那么a就不能在30分钟的时候, 被清理了. 另外还有下面第三个原因.PHP默认的(Linux为例), 是使用/tmp 作为Session的默认存储目录, 并且手册中也有如下的描述:Note: 如果不同的脚本具有不同的 session.gc_maxlifetime 数值但是共享了同一个地方存储会话数据,则具有最小数值的脚本会清理数据。此情况下,与 session.save_path 一起使用本指令。也就是说, 如果有俩个应用都没有指定自己独立的save_path, 一个设置了过期时间为2分钟(假设为A), 一个设置为30分钟(假设为B), 那么每次当A的Session gc运行的时候, 就会同时删除属于应用B的Session files.所以, 第一种答案是不"完全严格"正确的.第二种答案还有一种常见的答案是: 设置Session ID的载体, Cookie的过期时间, 也就是session.cookie_lifetime. 这种回答也是不正确的, 原因如下:这个过期只是Cookie过期, 换个说法这点就考察Cookie和Session的区别, Session过期是服务器过期, 而Cookie过期是客户端(浏览器)来保证的, 即使你设置了Cookie过期, 这个只能保证标准浏览器到期的时候, 不会发送这个Cookie(包含着Session ID), 而如果通过构造请求, 还是可以使用这个Session ID的值.第三种答案使用memcache, redis等, okey, 这种答案是一种正确答案. 不过, 很显然出题者肯定还会接着问你, 如果只是使用PHP呢?第四种答案当然, 面试不是为了难道你, 而是为了考察思考的周密性. 在这个过程中我会提示出这些陷阱, 所以一般来说, 符合题意的做法是:设置Cookie过期时间30分钟, 并设置Session的lifetime也为30分钟.自己为每一个Session值增加Time stamp.每次访问之前, 判断时间戳.最后, 有同学问, 为什么要设置30分钟的过期时间: 这个, 首先这是为了面试, 第二, 实际使用场景的话, 比如30分钟就过期的优惠劵?
2023年08月04日
14 阅读
0 评论
0 点赞
1
...
103
104
105
...
112