1. 程式人生 > >web 安全與效能

web 安全與效能

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>

Nginx / lighttpd + fastcgi

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/php7/fpm/pool.d/www.conf

user = www
group = www


chdir = /
改為
chdir = /var/www


chroot = /var/www
這樣當用戶試圖通過chdir跳轉到/var/www以外的目錄是,將被拒絕

web server 版本資訊

Apache:
ServerTokens ProductOnly
ServerSignature Off

Nginx:
server_tokens off;

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

伺服器防止URL注入

if ($request_uri ~* (.*)(insert|select|delete|update|count|concat|cost|union|drop|table|*|%|master|truncate|declare|'|;|and|or|(|)|exec)(.*)$ ) 
{ 
    return 403; 
}
if ( $query_string ~* ".*[;'<>].*" ){
    return 403;
}

php.ini

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
對於後門植入主要是用下面幾個方法

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.隱藏PHP版本資訊

expose_php Off

3.session名字可以洩露你的伺服器採用php技術

session.name = PHPSESSID
偽裝成Tomcat
session.name = JSESSIONID

4. 隱藏PHP出錯資訊

display_errors = Off
同時開啟error_log日誌
error_log = php_errors.log

5.open_basedir 防止操作web環境意外檔案目錄

open_basedir = /www/:/tmp/

如果要設定多個目錄,window使用;分隔目錄,Linux使用:分隔目錄。 

開發於安全

1.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]
    }
}

上面程式碼僅供參考,未做過執行測試

注入安全

1.禁止輸出除錯資訊

error_reporting(0);

2. 預防SQL注入攻擊
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.SHELL 命令注入

SHELL 命令注入, 原理是PHP中``符號或者system,exec等等函式會執行系統命令。

1、儘量不要執行外部命令

2、使用自定義函式或函式庫來替代外部命令的功能

3、使用escapeshellarg函式來處理命令引數

4、使用safe_mode_exec_dir指定可執行檔案的路徑

esacpeshellarg函式會將任何引起引數或命令結束的字元轉義,單引號“’”,替換成“\’”,雙引號“"”,替換成“\"”,分號“;”替換成“\;”

用safe_mode_exec_dir指定可執行檔案的路徑,可以把會使用的命令提前放入此路徑內

safe_mode = On

safe_mode_exec_dir = /usr/local/php/bin/

執行效率

如果是web應用程式,通常我們必須將執行時間控制在30秒以內, 10秒最佳. 否則使用者是沒有耐心等待你的網站開啟.

1.timeout

下面的流程展示了從使用者開啟瀏覽器到頁面展示出來的整個流程, 每個流程都可能出現 timeout

user -> dns -> web server -> app server -> cache -> database

嚴格限制執行時間

外部引用域名必須寫入hosts檔案, 防止解析時間過長

必須設定嚴格的超時策略, 方式程式長時間等待不退出, 佔用系統資源

<?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);
?>

2.mysql

show variables like '%timeout%'

3.瀏覽器上傳檔案尺寸控制

Nginx

client_max_body_size 8M

設定不能過大,因為可以通過你的網站上傳功能,持續上傳實現攻擊。