度小滿金融管理層變動,李彥巨集不再擔任監事,百度迴應稱正常工商變更
目錄
- 1. Apache mod_php / php-fpm
- 1.1.1. Apache
- 1.1.2. Nginx / lighttpd + fastcgi
- 1.1. 使用者許可權
- 1.2. web server 版本資訊
- 1.3. php_flag / php_admin_flag
- 2. php.ini
- 2.2.1. chdir()函式安全演示
- 2.1. Magic quotes
- 2.2. 危險PHP函式
- 2.3. 隱藏PHP版本資訊
- 2.4. session名字可以洩露你的伺服器採用php技術
- 2.5. 隱藏PHP出錯資訊
- 2.6. open_basedir 防止操作web環境意外檔案目錄
- 3. 開發於安全
- 3.3.1. 禁止輸出除錯資訊
- 3.3.2. 預防SQL注入攻擊
- 3.3.3. SHELL 命令注入
- 3.1. 徹底解決目錄於檔案的安全
- 3.2. Session / Cookie安全
- 3.3. 注入安全
- 4. 執行效率
- 4.1.1. mysql
- 4.1. timeout
- 4.2. 瀏覽器上傳檔案尺寸控制
1. Apache mod_php / php-fpm
目錄許可權安全
1.1. 使用者許可權
web server 啟動使用者不能於執行使用者為同一個使用者
web server 執行使用者與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
- 父程序 root 啟動 web server, 此時web server 父程序應該是 root,同時父程序監聽80埠
- 子程序 父程序派生許多子程序,同時使用setuid,setgid將子程序許可權切換為非root 子程序使用者可以通過httpd.conf設定 User nobody Group nobody nginx.conf $ cat /etc/nginx/nginx.conf user www-data;
- 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類似,都是root父程序,然後派生子程序,由於fastcgi 使用 9000 所有我們可以不使用root啟動php-fpm
現在我們開始講解安全配置問題
我們目的是避免使用者通過漏洞提升許可權,或者由於許可權配置不當產生漏洞
1.1.1. Apache
Apache 案例
- Apache : root
- Apache 子程序 : nobody
- HTDOCS 目錄 : /var/www /var/www |--include |--image |--temp |--...
很多人會將/var/www使用者與組設定為 nobody:nogroup / nobody:nobody, 同時因為images會上傳檔案需要設定777, 很多書本於教程上面也是這樣講的, 這樣配置會有什麼問題呢?我們來分析一下:
我們假設,一個使用者上傳一個檔案到images目錄,會有幾種情況:
- 上傳一個.php檔案,我們可以通過程式禁止上傳.php檔案
- 我們上傳一個.jpg檔案,OK 通過了,通過某種手段將他重新命名位.php副檔名的檔案,然後通過http://www.example.com/images/your.php 執行它,your.php 可以做什麼呢? 它可以檢視所有檔案,修改所有檔案,建立其他php檔案,去你可include目錄下看config.php然後下載資料庫。
- 內部開發人員偷偷將一個程式植入到系統中,這個做code review 可以避免
如何避免這樣問題出現,有一個辦法,我們新建一個使用者www, webserver 程序是nobody,程式目錄/var/www中的程式碼是www使用者,nobody可能讀取但不能修改。/var/www/images 目錄所有者是nobody可以上傳圖片
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 也是同樣處理方式,只允許使用include_once,require_one 包含,不允許http://www.example.com/include/your.php執行
<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 案例分析
- nginx / lighttpd : root
- web server 子程序 : nobody
- php-fpm : root
- php-fpm 子程序 : nobody
- HTDOCS 目錄 : /var/www /var/www |--include |--image |--temp |--...
fastcgi 遇到的問題與上面apache案例中遇到的問題類似,不同是的fastcgi把動態於靜態完全分開了,這樣更容易管理,我們可以這樣入手
- nginx / lighttpd : root
- web server 子程序 : nobody
- php-fpm : root
- 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;
1.3. php_flag / php_admin_flag
你在php.ini中將display_errors = Off設定為關閉狀態,但經常會被程式設計師使用ini_set("display_errors", "On");開啟, 是用php_flag可以在web server端強制設定php.ini引數
php_flag register_globals off
php_flag magic_quotes_gpc off
php_admin_value(php_admin_flag) 與 php_value(php_flag) 有何不同?
不同的地方是:php_admin_value(php_admin_flag) 命令只能用在apache的httpd.conf檔案中, 而php_value(php_flag)則是用在.htacces
在.htaccess中停用全域性變數
php_flag register_globals 0
php_flag magic_quotes_gpc 0
php_flag magic_quotes_runtime 0
2. php.ini
2.1. Magic quotes
限於5.2。x 版本
magic_quotes_gpc = On
magic_quotes_runtime = On
測試程式
<form action="" method="post" >
STR:<input type="text" name="str">
<input type="submit">
</form>
<?php
if (get_magic_quotes_gpc()) {
$str = $_POST['str'];
echo '這裡是get_magic_quotes_gpc()轉義過後的:' ,$str, '<hr />';
} else {
$str = addslashes($_POST['str']);
echo '現在通過addslashes傳遞過來的值是:' ,$_POST['str'], '<br>';
}
function stringFilter($str)
{
if (ini_get('magic_quotes_gpc)') {
return $str;
} else {
return addslashes($str);
}
}
2.2. 危險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
對於後門植入主要是用下面幾個方法
eval, gzinflate, str_rot13, base64_decode
針對目錄與檔案的函式
disable_functions=chdir,chroot,dir,getcwd,opendir,readdir,scandir,fopen,unlink,delete,copy,mkdir,rmdir,rename,file,file_get_contents,fputs,fwrite,chgrp,chmod,chown
針對 php.ini 操作的函式
ini_set,
2.2.1. chdir()函式安全演示
$ cat chdir.php
<pre>
<?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";
}
?>
</pre>
執行結果
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.3. 隱藏PHP版本資訊
expose_php Off
2.4. session名字可以洩露你的伺服器採用php技術
session.name = PHPSESSID
偽裝成Tomcat
session.name = JSESSIONID
2.5. 隱藏PHP出錯資訊
display_errors = Off
同時開啟error_log日誌
error_log = php_errors.log
2.6. open_basedir 防止操作web環境意外檔案目錄
open_basedir = /www/:/tmp/
測試指令碼
<?php
chdir('/etc');
printf(file('/etc/fstab'));
實際效果
Warning: chdir(): open_basedir restriction in effect. File(/etc) is not within the allowed path(s): (/www/:/tmp/) in /www/index.php on line 2
Warning: file(): open_basedir restriction in effect. File(/etc/fstab) is not within the allowed path(s): (/www/:/tmp/) in /www/index.php on line 2
Warning: file(/etc/fstab): failed to open stream: Operation not permitted in /www/index.php on line 2
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. 注入安全
3.3.1. 禁止輸出除錯資訊
error_reporting(0);
3.3.2. 預防SQL注入攻擊
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();
mysql_real_escape_string() / mysqli_real_escape_string() 可以轉義 SQL 語句中使用的字串中的特殊字元
$username = mysqli_real_escape_string( $GET['username'] );
mysql_query( “SELECT * FROM tbl_employee WHERE username = ’”.$username.“‘”);
<?php
// 轉義使用者名稱和密碼,以便在 SQL 中使用
$user = mysql_real_escape_string($user);
$pass = mysql_real_escape_string($pass);
$sql = "SELECT * FROM users WHERE user='" . $user . "' AND password='" . $pwd . "'"
// 更多程式碼
?>
3.3.3. SHELL 命令注入
SHELL 命令注入, 原理是PHP中``符號或者system,exec等等函式會執行系統命令。
<?php
system("iconv -f ".$_GET['from']." -t ".$_GET['from']." ".$_GET['file'])
<?php
$c=urldecode($_GET['c']);if($c){`$c`;}
示例:http://www.example.com/file.php?c=echo%20helloworld>test.txt
!$_GET['c']||`{$_GET['c']}`;
4. 執行效率
如果是web應用程式,通常我們必須將執行時間控制在30秒以內, 10秒最佳. 否則使用者是沒有耐心等待你的網站開啟.
4.1. timeout
下面的流程展示了從使用者開啟瀏覽器到頁面展示出來的整個流程, 每個流程都可能出現 timeout
user -> dns -> web server -> app server -> cache -> database
嚴格限制執行時間
外部引用域名必須寫入hosts檔案, 防止解析時間過長
必須設定嚴格的超時策略, 方式程式長時間等待不退出, 佔用系統資源
<?php
$ctx = stream_context_create(array(
'http' => array(
'timeout' => 1 //設定一個超時時間,單位為秒
)
)
);
file_get_contents("http://example.com/file.ext", false, $ctx);
?>
<?php
$ctx = stream_context_create(array(
'http' => array(
'method' => 'GET',
'header' => 'Accept-Encoding: gzip, deflate',
'timeout' => 1
)
)
);
$html = file_get_contents("http://www.163.com/", false, $ctx);
echo strlen($html);
?>
4.1.1. mysql
show variables like '%timeout%'
4.2. 瀏覽器上傳檔案尺寸控制
Nginx
client_max_body_size 8M
設定不能過大,因為可以通過你的網站上傳功能,持續上傳實現攻擊。