Tagged: 安全

秒懂系列|Apache用户认证配置之Basic认证

很多时候我们可能需要对服务器资源进行保护,通常的做法是在应用层通过鉴权来实现,如果你嫌自己去实现鉴权太麻烦,那就直接让Apache去帮你实现吧!
Apache常见的用户认证可以分为下面三种:
- 基于IP,子网的访问控制(ACL)
- 基本用户验证(Basic Authentication)
- 消息摘要式身份验证(Digest Authentication)

基于IP的访问控制可以通过配置 Allow From实现!这里不多讲。
一般的,我们还会在IP的基础上,再增加一层 Basic Authentication,实现一个基本的服务器用户认证!

1、生成用户名密码文件

/usr/local/apache2/bin/htpasswd -bc users.pwd test hehe1234

Adding password for user test

/usr/local/apache2/bin/htpasswd -b users.pwd test2 hehe4321

Adding password for user test2

cat users.pwd

test:$apr1$4R3foyQ5$1KGHVA5HQL8M9b0K/2UWO0
test2:$apr1$pKLy86CD$W9hFUvs4F06OBXtQhCbPV/

可以看到用户名密码文件已经生成了,一行一个!

2、配置 VirtualHost,如:

<VirtualHost *:80>
    DocumentRoot /usr/local/www/pma/
    DirectoryIndex index.php index.html index.shtml
    ServerName pma.979137.com
    CustomLog "logs/pma.979137.com-access_log" common
    ErrorLog "logs/pma.979137.com-error_log"
    <Directory /usr/local/www/pma/>
        Options Includes FollowSymLinks
        AllowOverride AuthConfig
        AuthName "PMA Contents." 
        AuthType basic
        AuthUserFile /usr/local/apache/conf/users.pwd 
        Require valid-user
    </Directory>
</VirtualHost>
  • AllowOverride 表示通过配置文件进行身份验证
  • AuthName 发送给客户端报文头内容:WWW-Authenticate
  • AuthType 认证类型
  • AuthUserFile 这个就是刚刚生成的用户名密码文件
  • Require 指定哪些用户或组才能被授权访问。如:
    • require user test test2(只有用户 test 和 test2 可以访问)
    • requires groups managers (只有组 managers 中成员可以访问)
    • require valid-user (在 AuthUserFile 指定的文件中任何用户都可以访问)

我们来看一下效果:

在浏览器访问:

cURL请求:

curl -v http://pma.979137.com/test.php

* Trying 10.223.28.1...
* Connected to pma.979137.com (10.223.28.1) port 80 (#0)
> GET /test.php HTTP/1.1
> Host: pma.979137.com
> User-Agent: curl/7.43.0
> Accept: */*>
< HTTP/1.1 401 Authorization Required < Date: Fri, 06 Jan 2017 07:02:15 GMT < Server: Apache/2.2.27 (Unix) PHP/5.3.29 < WWW-Authenticate: Basic realm=" PMA Contents." < Content-Length: 490 < Content-Type: text/html; charset=iso-8859-1 < >401 Authorization Required
>Authorization Required
This server could not verify that you
are authorized to access the document
requested. Either you supplied the wrong
credentials (e.g., bad password), or your
browser doesn't understand how to supply
the credentials required.

在没有携带用户名和密码时,HTTP Code 返回了 401,并输出了 Authorization Required!
表示需要该请求需要进行认证!

我们再来看下,携带密码请求:

curl -v -u 'test:hehe1234' 'http://pma.979137.com/test.php'

* Trying 10.223.28.1...
* Connected to pma.979137.com (10.223.28.1) port 80 (#0)
* Server auth using Basic with user 'test'
> GET /test.php HTTP/1.1
> Host: pma.979137.com
> Authorization: Basic c2hpbGlhbmd4aWU6YWl5aTEzMTQ=
> User-Agent: curl/7.43.0
> Accept: */*
>
< HTTP/1.1 200 OK < Date: Fri, 06 Jan 2017 07:14:14 GMT < Server: Apache/2.2.27 (Unix) PHP/5.3.29 < X-Powered-By: PHP/5.3.29 < Content-Length: 25 < Content-Type: text/html < string(11) "hello word!"

HTTP Code 已经是 200 了,并且返回了正确的内容!
至此,一个简单的 Basic 认证就OK了!这种认证一般可用于浏览器访问,也可以用于 API 认证!

秒懂系列|Apache保护文件和目录及来源IP限制实现

访问网站目录时 Apache 默认配置为可列出目录/文件列表,即当你访问http://localhost 时会列出相关的目录和文件列表;有时我们需要控制某个目录或某个文件不被访问,比如常见的WIKI系统,文档数据(一般是txt文件)就必须不能被访问,否则将出现安全隐患;
我们可以通过修改 Apache 配置文件来实现禁止列出目录/文件列表(当然,你也可以通过 .htaccess 来实现)

一、禁止访问某些文件/目录

1、增加Files选项来控制,比如要不允许访问 .yaml 扩展名的文件,保护配置文件:

<Files ~ ".yaml$">
    Order allow,deny
    Deny from all
</Files>

2、禁止访问某些指定的目录:(可以用 来进行正则匹配)

<Directory ~ "^/home/www/sites/(.+/)*[0-9]{3}">
    Order allow,deny
    Deny from all
</Directory>

3、通过文件匹配来进行禁止,比如禁止所有针对图片的访问:

<FilesMatch .(?i:gif|jpe?g|png)$>
    Order allow,deny
    Deny from all
</FilesMatch>

4、针对URL相对路径的禁止访问,比如dokuwiki系统就必须保护下列目录:

<Location ~ "^/wiki/(data|conf|bin|inc)">
    Order allow,deny
    Deny from all
</Location>

5、针对代理方式禁止对某些目标的访问( 可以用来正则匹配),比如拒绝通过代理访问 979137.com:

<Proxy https://979137.com/*>
    Order allow,deny
    Deny from all
</Proxy>

二、禁止某些IP访问/只允许某些IP访问

1、如果要控制禁止某些非法IP访问,在Directory选项控制:

<Directory "/home/www/sites/">
    Order allow,deny
    Allow from all
    Deny from 10.0.0.1 #阻止一个IP
    Deny from 192.168.0.0/24 #阻止一个IP段
</Directory>

2、只允许某些IP访问,适合比如就允许内部或者合作公司访问:

<Directory "/home/www/sites/">
    Order deny,allow
    Deny from all
    All from example.com #允许某个域名
    All from 10.0.0.1 #允许一个iP
    All from 10.0.0.1 10.0.0.2 #允许多个iP
    Allow from 10.1.0.0/255.255.0.0 #允许一个IP段,掩码对
    All from 10.0.1 192.168 #允许一个IP段,后面不填写
    All from 192.168.0.0/24 #允许一个IP段,网络号
</Directory>

PHP,CURL和你的安全!

如果最近你在美国看电视,你会经常看到一个这样的广告:

一个和蔼友善的家伙说“我希望我的电脑被病毒感染”,
“我希望所有我家的照片都被人删除,找不回来。”

“我希望我的笔记本运转的声音听起来像打雷。”

当然,没有一个正常人希望遇到这样的痛苦,但如果你不对自己的电脑采取保护措施,结果就是让黑客得逞。
你需要理解,这就像在你家里,车或钱袋子,你不能让它们都敞着口放在外面,你不能认为陌生路人都是可信的。
大部分的陌生人并不像你想象的那样友好。

如果没有人告诉你应该怎么做,你很容易犯错误。置之不理是愚蠢的,幸好你读了这篇文章。我要首先假设你不是那么愚蠢的人。

不应该做的事情

下面是一个列表,解释了什么不该做,以及为什么。

这是外表美味可口巧克力,里面却藏着恶魔。它的意思是

去 www.webhek.com 网站,取回页面内容,运行这些内容,不论是什么内容。

如果是像下面的这些内容到无所谓:

Hello World

但是,如果你不那么幸运,这个网站被人动过手脚,它的内容被替换成:

Evil ruuLzzzzorz!!!

这句代码会删除你的电脑上的所有东西。

这样会稍微安全一些,因为这句代码的做法是读取远程页面的内容,然后打印它们。即使有人在内容里插入了恶意的PHP代码,这些代码也没有机会被执行。
但是,黑客仍然可以在内容里注入恶意的 JavaScript,你会发现你的页面上突然间被植入了无数的弹出式广告窗口页面。
这会让你的网站的浏览者非常恼怒。这里面有很多的学问,但上面这些是最大的问题。

应该如何做

PHP里面有一个非常强大的函数库,它们的目的就是让你安全的从远程网站上取回内容。
这些函数被称作CURL。现在,你不要被CURL官方页面上大量的东西吓阻,它实际上非常的简单。

下面是一个简单的替换上面read_file()命令的做法:

<?php
$curl_handle=curl_init();
curl_setopt($curl_handle,CURLOPT_URL,'http://www.webhek.com');
curl_exec($curl_handle);
curl_close($curl_handle);

就是这样,这才是你应该做的,最后一句 curl_close() 不是必要的。

小心,你仍然有被远程网站上的恶意 JavaScript 和 cookie 盗取者袭击的风险。
防范这些攻击需要牵涉到更多的内容。如果你想做这些,我建议你使用PHP正则表达式函数里的 preg_replace()。

假设我们确实要用CURL来做一些事情。假设 www.webhek.com 这个网站不是那么稳定。它有时候会没有响应,一个页面需要30秒才能拉取成功。对于这种情况,我们的办法是:

<?php
$curl_handle=curl_init();
curl_setopt($curl_handle,CURLOPT_URL,'http://www.webhek.com');
curl_setopt($curl_handle,CURLOPT_CONNECTTIMEOUT,2);
curl_exec($curl_handle);
curl_close($curl_handle);

这种写法是说,2秒钟内如果不能抓取完数据就做超时处理。
是的,也许你更愿意设定为1秒就算超时,因为它妨碍你的页面的速度。(注意,不要设置为0,这是告诉curl没有超时限制。)

但是,如果是什么东西都没有取回了,你想显示一个提示信息,这该怎么办?哈哈,简单!

<?php
$curl_handle=curl_init();
curl_setopt($curl_handle,CURLOPT_URL,'http://www.webhek.com');
curl_setopt($curl_handle,CURLOPT_CONNECTTIMEOUT,2);
curl_setopt($curl_handle,CURLOPT_RETURNTRANSFER,1);
$buffer = curl_exec($curl_handle);
curl_close($curl_handle);

if (empty($buffer)) {
    print "抱歉,webhek.com 这个网站又无响应了。<p>";
} else {
    print $buffer;
}
Return Top