PHP保険

WBOY
リリース: 2016-06-13 13:18:43
オリジナル
1035 人が閲覧しました

PHP セキュリティ

PHP セキュリティ

http://netkiller.github.com/article/phpsecurity.html

ミスター.?ネオ・チェン?(ネットキラー),?陈京峰(BG7NYT)


概要

?

以下は、長年にわたって蓄積された私の経験の要約であり、参考のために文書にまとめられています:

?

Netkiller Architect 手札 Netkiller Linux 手札 Netkiller Developer 手札 Netkiller Database 手札
Netkiller Debian 手札 Netkiller CentOS 手札 Netkiller FreeBSD 手札 Netkiller Shell 手札
Netkiller Web 手札 Netkiller Monitoring 手札 Netkiller Storage 手札 Netkiller Mail 手札
Netkiller Security 手札 Netkiller Multimedia 手札 Netkiller Writer 手札 Netkiller Version 手札
Netkiller PostgreSQL 手札 Netkiller MySQL 手札 Netkiller Cryptography 手札 Netkiller Cisco IOS 手札
Netkiller LDAP 手札 Netkiller Intranet 手札 ? ?

?


目次

1.Apache mod_php / php-fpm
1.1. ユーザー権限
1.1.1.Apache
1.1.2. Nginx/lighttpd + fastcgi
1.2. Web サーバーのバージョン情報
2.php.ini
2.1. 危険な PHP 関数
2.1.1. chdir() 関数の安全性のデモ
2.2. PHP バージョン情報を非表示にする
2.3. PHP エラーメッセージを非表示にする
3. 安全性を考慮して開発されました
3.1. ディレクトリとファイルのセキュリティを完全に解決します
3.2. セッション/Cookie のセキュリティ
3.3. インジェクションセキュリティ

1.?Apache mod_php/php-fpm

ディレクトリ権限のセキュリティ

1.1.?ユーザー権限

Web サーバーの起動ユーザーを実行ユーザーと同じユーザーにすることはできません

Web サーバーを実行しているユーザーと PHP プログラムを同じユーザーにすることはできません

root      1082  0.0  0.1  11484  2236 ?        Ss   Mar01   0:00 nginx: master process /usr/sbin/nginx
www-data 13650  0.0  0.0  11624  1648 ?        S    09:44   0:00 nginx: worker process
www-data 13651  0.0  0.0  11624  1132 ?        S    09:44   0:00 nginx: worker process
www-data 13652  0.0  0.0  11624  1132 ?        S    09:44   0:00 nginx: worker process
www-data 13653  0.0  0.0  11624  1132 ?        S    09:44   0:00 nginx: worker process
			
ログイン後にコピー
  1. プロセス

    root は Web サーバーを起動します。このとき、Web サーバーの親プロセスは root である必要があり、親プロセスはポート 80 をリッスンします。

  2. 子プロセス

    親プロセスは多くの子プロセスを生成し、setuid と setgid を使用して子プロセスの権限を非 root に切り替えます

    サブプロセスユーザーは httpd.conf を通じて設定できます

    User nobody
    Group nobody
    					
    ログイン後にコピー

    nginx.conf

    $ cat /etc/nginx/nginx.conf 
    user www-data;					
    					
    ログイン後にコピー
  3. fastcgi プロセス

    root     13082  0.0  0.1  19880  2584 ?        Ss   09:28   0:00 php-fpm: master process (/etc/php5/fpm/php-fpm.conf)      
    www-data 13083  0.0  0.1  20168  3612 ?        S    09:28   0:00 php-fpm: pool www                                         
    www-data 13084  0.0  0.1  20168  2808 ?        S    09:28   0:00 php-fpm: pool www                                         
    www-data 13085  0.0  0.1  20168  2812 ?        S    09:28   0:00 php-fpm: pool www                                         
    www-data 13086  0.0  0.1  20168  2812 ?        S    09:28   0:00 php-fpm: pool www 
    					
    ログイン後にコピー

    php-fpm は apache に似ており、両方ともルートの親プロセスであり、その後、子プロセスを派生します。fastcgi は 9000 を使用するため、root を使用せずに php-fpm を起動できます。

ここからはセキュリティ構成の問題について説明していきます

私たちの目的は、ユーザーが脆弱性を利用して権限を昇格したり、不適切な権限設定により脆弱性を作成したりすることを防ぐことです

1.1.1.?Apache

Apache のケース

  1. Apache : ルート

  2. Apache 子プロセス: 誰も

  3. HTDOCS ディレクトリ: /var/www

    		
    /var/www
    |--include
    |--image
    |--temp
    |--...	
    						
    ログイン後にコピー
    ログイン後にコピー

多くの人は、/var/www ユーザーとグループを none:nogroup / nothing:nobody に設定します。同時に、画像はファイルをアップロードするため、777 に設定する必要があります。多くの本のチュートリアルにもこれが記載されています。 . この構成の問題点は何ですか?それを分析してみましょう:

ユーザーがファイルを画像ディレクトリにアップロードすると想定します。以下のような状況が考えられます。

  1. .php ファイルをアップロードします。プログラムを通じて .php ファイルのアップロードを禁止できます

  2. .jpg ファイルをアップロードし、OK に成功したら、何らかの方法でファイル名を .php 拡張子ファイルに変更して、http://www.example.com/images/your.php を通じて実行します。 phpはしますか? すべてのファイルの表示、すべてのファイルの変更、他の PHP ファイルの作成、インクルード ディレクトリ内の config.php の確認、データベースのダウンロードが可能です。

  3. 社内開発者が密かにシステムにプログラムを埋め込むこれは、コードレビューを行うことで回避できます。

この問題を回避する方法はあります。新しいユーザー www を作成します。Web サーバー プロセスは誰もいません。プログラム ディレクトリ /var/www 内のコードは www ユーザーです。誰も読み取ることはできませんが、変更することはできません。 。 /var/www/images ディレクトリの所有者は誰もいないため、画像をアップロードできます

				
chown www /var/www/
chown nobody /var/www/images
find /var/www/ -type d -exec chmod 555 {} \;
find /var/www/ -type f -exec chmod 444 {} \;
chmod 755 /var/www/images
				
				
ログイン後にコピー
可能なすべてのディレクトリを有効にして .php ファイルの実行を許可します。http://www.example.com/images/your.php は同じ方法で処理されます。include_once のみが許可され、require_one は許可されます。許可されません: //www.example.com/include/your.php run

		
				
<Location ~ "/((js/)|(css/)|(images/)).*\.php">
	Order Deny,Allow
	Deny from all
</Location>	

<Location /includes/>
        Order allow,deny
        Deny from all
</Location>
<Location /library/>
        Order allow,deny
        Deny from all
</Location>		

<Directory /var/www/themes/>
    <Files *.php>
		Order allow,deny
		Deny from all
    </Files>
</Directory>
					
				
ログイン後にコピー

1.1.2.?Nginx/lighttpd + fastcgi

Nginx / lighttpd のケース分析

  1. nginx/lighttpd:root

  2. Web サーバーの子プロセス: 誰も

  3. php-fpm : ルート

  4. php-fpm 子プロセス: 誰も

  5. HTDOCS ディレクトリ: /var/www

    		
    /var/www
    |--include
    |--image
    |--temp
    |--...	
    						
    ログイン後にコピー
    ログイン後にコピー

fastcgi 遇到的问题与上面apache案例中遇到的问题类似,不同是的fastcgi把动态于静态完全分开了,这样更容易管理,我们可以这样入手

  1. nginx / lighttpd : root

  2. web server 子进程 : nobody

  3. php-fpm : root

  4. php-fpm 子进程 : www

chown nobody /var/www/
chown www /var/www/images
find /var/www/ -type d -exec chmod 555 {} \;
find /var/www/ -type f -exec chmod 444 {} \;
chmod 755 /var/www/images
				
ログイン後にコピー

/var/www所有权限给nobody, images权限给www, 同时保证www用户可以读取/var/www下的程序文件

location ~ ^/upload/.*\.php$
{
        deny all;
}

location ~ ^/static/images/.*\.php$
{
        deny all;
}
		
location ~ /include/.*\.php$ {
    deny all;
}

location ~ .*\.(sqlite|sq3)$ {
    deny all;
}

				
ログイン後にコピー
vim /etc/php5/fpm/pool.d/www.conf

user = www
group = www
				
ログイン後にコピー

/etc/php5/fpm/pool.d/www.conf

chdir = /
改为
chdir = /var/www
				
ログイン後にコピー

chroot可以彻底解决cd跳转问题,单配置比较繁琐

chroot = /var/www
				
ログイン後にコピー

这样当用户试图通过chdir跳转到/var/www以外的目录是,将被拒绝

1.2.?web server 版本信息

Apache:
ServerTokens ProductOnly
ServerSignature Off

Nginx:
server_tokens off;
			
ログイン後にコピー

2.?php.ini

2.1.?危险PHP函数

这些函数应该尽量避免使用它们

exec, system, ini_alter, readlink, symlink, leak, proc_open, popepassthru, chroot, scandir, chgrp, chown, escapeshellcmd, escapeshellarg, shell_exec, proc_get_status, max_execution_time, opendir,readdir, chdir ,dir, unlink,delete,copy,rename
			
ログイン後にコピー

2.1.1.?chdir()函数安全演示

				
$ cat chdir.php 
<pre class="brush:php;toolbar:false">
<?php
echo "current:".getcwd();
echo '<br />';
chdir('/');
echo "chdir:".getcwd();
echo '<br />';
$lines = file('etc/passwd');

foreach ($lines as $line_num => $line) {
    echo "Line #<b>{$line_num}</b> : " . htmlspecialchars($line) . "<br />\n";
}
?>
ログイン後にコピー

运行结果

current:/www
chdir:/
Line #0 : root:x:0:0:root:/root:/bin/bash
Line #1 : daemon:x:1:1:daemon:/usr/sbin:/bin/sh
Line #2 : bin:x:2:2:bin:/bin:/bin/sh
Line #3 : sys:x:3:3:sys:/dev:/bin/sh
Line #4 : sync:x:4:65534:sync:/bin:/bin/sync
Line #5 : games:x:5:60:games:/usr/games:/bin/sh
				
ログイン後にコピー

2.2.?隐藏PHP版本信息

?

expose_php Off
			
ログイン後にコピー

2.3.?隐藏PHP出错信息

display_errors = Off
			
ログイン後にコピー
同时开启error_log日志
error_log = php_errors.log			
			
ログイン後にコピー

3.?开发于安全

3.1.?彻底解决目录于文件的安全

选择一个MVC开发框架,它们的目录结构一般是这样的:

/www
/www/htdocs/index.php	htdocs目录下只有一个index.php文件,他是MVC/HMVC框架入口文件
/www/htdocs/static		这里防止静态文件		
/www/app/				这里放置php文件
			
ログイン後にコピー

然后放行index.php文件,在URL上不允许请求任何其他php文件,并返回404错误

3.2.?Session / Cookie安全

session.save_path 默认session 存储在/tmp, 并且一明文的方式将变量存储在以sess_为前缀的文件中

			
$ cat session.php 
<?php
session_start();

if(isset($_SESSION['views']))
  $_SESSION['views']=$_SESSION['views']+1;
else
  $_SESSION['views']=1;
echo "Views=". $_SESSION['views'];
?>

			
			
ログイン後にコピー

http://www.example.com/session.php 我们刷新几次再看看sess_文件中的变化

$ cat /tmp/sess_d837a05b472390cd6089fc8895234d1a
views|i:3;
			
ログイン後にコピー

经过侧记你可以看到session文件中存储的是明文数据,所以不要将敏感数据放到Session中,如果必须这样作。建议你加密存储的数据

有一个办法比较好,就是封装一下session.不再采用$_SESSION方式调用

			
Class Encrype{

}			
			
Class Session extend Encrype {

	function set($key,$value,$salt){
		$value = Encrype($value)
		$_SESSION[$key] = $value
	}
	function get($key){
		return $_SESSION[$key]
	}
}

Class Cookie extend Encrype {

	function set($key,$value,$salt){
		$value = Encrype($value)
		$_COOKIE[$key] = $value
	}
	function get($key){
		return $_COOKIE[$key]
	}
}
			
			
ログイン後にコピー

Cookie

cookie 也需要作同样的处理,上面代码仅供参考,未做过运行测试

3.3.?注入安全

SQL 注入

			
<?php
    $mysql_server_name="172.16.0.4";
    $mysql_username="dbuser";
    $mysql_password="dbpass";
    $mysql_database="dbname";


    $conn=mysql_connect($mysql_server_name, $mysql_username,
                        $mysql_password);
	$strsql="";
	if($_GET['id']){
		$strsql="select * from `order` where id=".$_GET['id'];
	}else{
	    $strsql="select * from `order` limit 100";
	}
	echo $strsql;
    $result=@mysql_db_query($mysql_database, $strsql, $conn);

    $row=mysql_fetch_row($result);

    echo '<font face="verdana">';
    echo '<table border="1" cellpadding="1" cellspacing="2">';


    echo "\n<tr>\n";
    for ($i=0; $i<mysql_num_fields($result); $i++)
    {
      echo '<td bgcolor="#000F00"><b>'.
      mysql_field_name($result, $i);
      echo "</b></td>\n";
    }
    echo "</tr>\n";

    mysql_data_seek($result, 0);

    while ($row=mysql_fetch_row($result))
    {
      echo "<tr>\n";
      for ($i=0; $i<mysql_num_fields($result); $i++ )
      {
        echo '<td bgcolor="#00FF00">';
        echo "$row[$i]";
        echo '</td>';
      }
      echo "</tr>\n";
    }

    echo "</table>\n";
    echo "</font>";

    mysql_free_result($result);

    mysql_close();

			
			
ログイン後にコピー

SHELL 命令注入

			
<?php
system("iconv -f ".$_GET['from']." -t ".$_GET['from']." ".$_GET['file'])
			
			
ログイン後にコピー
			
ログイン後にコピー
			

			
			
ログイン後にコピー
関連ラベル:
ソース:php.cn
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
最新の問題
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート