บทความก่อนหน้า: การดำเนินการหลังติดตั้ง CentOS 7

หลังจากที่ก่อนหน้านี้ ได้มีการแนะนำขั้นตอนที่ควรดำเนินการเพื่อความปลอดภัยในการใช้งาน หลังจากติดตั้ง RHEL 7/CentOS 7 แล้ว ในหัวข้อนี้จะขอกล่าวถึงขั้นตอนในการติดตั้ง LAMP (Linux, Apache, MariaDB, PHP) และ mod_security

ติดตั้ง Apache

เริ่มด้วยการติดตั้ง Apache จากคำสั่ง yum โดยจะมีการ ติดตั้ง package ที่เกี่ยวข้องหรือส่วนที่ apache ต้องการใช้งาน เพิ่มเติมมาให้ด้วย

[somchai@site2 ~]$ sudo yum install httpd

หลังจากติดตั้งเรียบร้อยแล้ว กำหนดให้ apache เริ่มทำงานตั้งแต่มีการเปิดเครื่องทุกครั้ง

[somchai@site2 ~]$ sudo systemctl enable httpd.service
ln -s '/usr/lib/systemd/system/httpd.service' '/etc/systemd/system/multi-user.target.wants
/httpd.service'

คำสั่งในการ start / stop / restart service

[somchai@site2 ~]$ sudo systemctl start httpd.service
[somchai@site2 ~]$ sudo systemctl restart httpd.service
[somchai@site2 ~]$ sudo systemctl stop httpd.service

คำสั่งในการตรวจสอบว่า httpd service ทำงานอยู่หรือไม่

[somchai@site2 ~]$ systemctl is-active httpd.service

ตรวจสอบ Firewall เพื่อให้เครื่อง client อื่นๆ สามารถ เรียกใช้งาน port 80 จาก server ได้

[somchai@site2 ~]$ sudo firewall-cmd --permanent --add-service=http
[somchai@site2 ~]$ sudo firewall-cmd --permanent --list-all
[somchai@site2 ~]$ sudo firewall-cmd --reload

ขั้นตอนการการตรวจสอบหา IP ตนเอง

[somchai@site2 ~]$ sudo ip addr list eth0 | awk '/inet /{sub(/\/[0-9]+/,"",$2); print $2}'
...#or
[somchai@site2 ~]$ sudo ip addr list

ทดสอบเรียกหน้า web http://[IP ADDRESS]/ หรือ Domain name ที่ตั้งค่าไว้แล้ว เพื่อนำมาทดสอบใช้งาน เช่น http://site2.example.com

ค่าเริ่มต้นต่างๆ สำหรับ httpd

Default config file: /etc/httpd/conf/httpd.conf
Configuration files which load modules : /etc/httpd/conf.modules.d/
Default ports: 80 และ 443 (SSL)
Default log files: /var/log/httpd/{access_log,error_log}

ติดตั้ง MariaDB

สำหรับ mariadb นั้น คือ Database ที่ทาง RedHat และ CentOS ได้เลือกเป็น Default แทน MySQL สำหรับใช้งานในส่วนของ database ซึ่ง MariaDB มีต้นสายมาจาก MySQL ดังนั้นการเปลี่ยนมาใช้งาน MariaDB แทนที่ MySQL จึงแทบจะไม่ต้องแก้ไข code ของ PHP เพิ่มเติม ก็ยังคงสามารถใช้งาน function ต่างๆ ได้

การติดตั้ง MariaDB

[somchai@site2 ~]$ sudo yum install mariadb-server mariadb

สั่ง start service

[somchai@site2 ~]$ sudo systemctl start mariadb.service

กำหนดให้ MariaDB เริ่มทำงานตั้งแต่มีการเปิดเครื่อง

[somchai@site2 ~]$ sudo systemctl enable mariadb.service

คำสั่งในการ start / stop / restart service

[somchai@site2 ~]$ sudo systemctl start mariadb.service
[somchai@site2 ~]$ sudo systemctl restart mariadb.service
[somchai@site2 ~]$ sudo systemctl stop mariadb.service

คำสั่งในการตรวจสอบว่า MariaDB service ทำงานอยู่หรือไม่

[somchai@site2 ~]$ systemctl is-active mariadb.service

กำหนดความปลอดภัยเพิ่มขึ้นให้กับ MariaDB server

[somchai@site2 ~]$ sudo /usr/bin/mysql_secure_installation
...
Enter current password for root (enter for none): กด enter ข้ามไป
Set root password? [Y/n] Y
New password: ใส่ password ที่ต้องการกำหนด
Re-enter new password: ใส่ password ที่ต้องการกำหนดอีกครั้ง
Remove anonymous users? [Y/n] Y
Disallow root login remotely? [Y/n] Y
Remove test database and access to it? [Y/n] Y
Reload privilege tables now? [Y/n] Y
...
All done! If you've completed all of the above steps, your MariaDB
installation should now be secure.

Thanks for using MariaDB!

หากแสดงข้อความดังกล่าว แสดงว่าดำเนินการเรียบร้อยแล้ว
สามารถทดสอบ login ได้ด้วยคำสั่ง

[somchai@site2 ~]$ sudo mysql -u root -p
Enter password: ใส่ค่า password ที่มีการกำหนดไว้ก่อนหน้านี้
Welcome to the MariaDB monitor. Commands end with ; or \g.
Your MariaDB connection id is 8
Server version: 5.5.40-MariaDB MariaDB Server

Copyright (c) 2000, 2014, Oracle, Monty Program Ab and others.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

MariaDB [(none)]>

กำหนดให้สามารถใช้งานผ่าน firewall

[somchai@site2 ~]$ sudo firewall-cmd --permanent --add-service=mysql
[somchai@site2 ~]$ sudo firewall-cmd --permanent --list-all
[somchai@site2 ~]$ sudo firewall-cmd --reload

ติดตั้ง PHP

เริ่มต้นจาก ติดตั้ง php และ extension ต่างๆ ที่ต้องการใช้งาน

[somchai@site2 ~]$ sudo yum install php php-devel php-gd php-imap php-ldap php-mysql 
php-odbc php-pear php-xml php-xmlrpc curl curl-devel perl-libwww-perl ImageMagick libxml2 
libxml2-devel

Restart apache เพื่อเริ่มต้นใช้งาน php

[somchai@site2 ~]$ sudo systemctl restart httpd.service

สร้างไฟล์ php เพื่อทดสอบ

[somchai@site2 ~]$ sudo vi /var/www/html/testphp.php
<?php
phpinfo(INFO_GENERAL);
?>

ทดสอบเรียกหน้า web : http://site2.example.com/testphp.php

ติดตั้ง mod_security

ModSecurity คือ web application firewall (WAF) ที่ใช้เพื่อตรวจสอบและป้องกันการบุกรุก รวมทั้งเพิ่มความปลอดภัยในการเรียกใช้งานที่ผิดประเภท สำหรับ Web server

เริ่มการติดตั้ง

[somchai@site2 ~]$ sudo yum install mod_security.x86_64

ตรวจสอบว่า apache มีการโหลดโมดูล mod_security มาใช้งานแล้ว

[somchai@site2 ~]$ sudo apachectl -M | grep --color security
security2_module (shared)

โดยส่วนที่เกี่ยวข้องกับการ config คือ

/etc/httpd/conf.d/mod_security.conf
/etc/httpd/modsecurity.d

เริ่มต้นการใช้งาน

[somchai@site2 ~]$ sudo systemctl restart httpd.service

การ config mod_security

การแก้ไข config เราจะเริ่มต้นที่ ไฟล์ mod_security.conf จากค่า default ของ config จะถูกกำหนดไว้เป็น DetectionOnly ซึ่งหมายถึงจะมีการตรวจสอบข้อมูลจาก rule ที่กำหนด แต่จะไม่มีการ block ค่าใดๆ ดังนั้นหากเราต้องการเปิดใช้งานสามารถแก้ไขค่าดังกล่าว หรือสามารถเปิดใช้งาน หลังจากที่มีการทดสอบส่วนต่างๆ เรียบร้อยแล้ว ก็ได้เช่นกัน

หากต้องการเปิดใช้งาน

[somchai@site2 ~]$ sudo vi /etc/httpd/conf.d/mod_security.conf

แก้ไขจาก

SecRuleEngine DetectionOnly > On

สำหรับ directive ที่จะมีการเปลี่ยนค่าตัวต่อไป คือ SecResponseBodyAccess เนื่องจาก เมื่อมีการเปิดการใช้งานในส่วนนี้ จะทำให้มีการเรียกใช้งานบัฟเฟอร์เพิ่มขึ้น และยังเพิ่มขนาดของไฟล์ log ให้มีขนาดใหญ่ขึ้น ดังนั้นเบื้องต้นเราจะปิดค่านี้ไปก่อน

ทั้งนี้เมื่อปิดการใช้งานในส่วน global ไปแล้ว สามารถเลือกเปิดใช้งาน ในบางช่วงสถานการณ์ที่เฉพาะเจาะจงสำหรับบางประเภทผ่าน directive : SecResponseBodyMimeType ได้

แก้ไขจาก

SecResponseBodyAccess On > Off

สำหรับ directive : SecRequestBodyLimit คือ การกำหนดค่าสูงสูดของขนาดข้อมูล POST ซึ่งหากข้อมูลมีขนาดใหญ่กว่าค่าที่กำหนดไว้ จะได้รับ Error : 413 “Request Entity Too Large” โดยค่านี้เหมาะสำหรับการปรับลดในกรณีที่ web site ไม่มีส่วนของการ upload ไฟล์ข้อมูลขนาดใหญ่ ดังนั้นเราจะแก้ไขเป็นค่าด้านล่าง ซึ่งประมาณ 12.5MB

SecRequestBodyLimit 13107200

อีก directive ที่มีลักษณะการทำงานคล้ายกันได้แก่ SecRequestBodyNoFilesLimit ซึ่งคือ การกำหนดค่าน้อยที่สุดของขนาดข้อมูล POST ซึ่งเราจะแก้ไขเป็นค่าด้านล่าง ประมาณ 128KB

SecRequestBodyInMemoryLimit 131072

การกำหนด path สำหรับการเก็บ debug log

SecDebugLog /var/log/httpd/modsec_debug.log

การกำหนดค่าของระดับการเก็บ log สามารถกำหนดค่าได้ตั้งแต่ 0-9 ซึ่งค่า default อยู่ที่ 0 สำหรับการใส่ค่า 1-3 log ดังกล่าวจะมีการเขียนลงที่ log ของ apache อยู่แล้ว หากต้องการตรวจสอบการใช้งาน สามารถปรับเพิ่มได้ ตามความเหมาะสม กรณีที่เครื่องที่มีการเปิดใช้งานแล้ว ไม่แนะนำให้มีการตั้งค่าสูงกว่า 3 เนื่องจาก อาจส่งผลกระทบกับประสิทธิภาพของระบบได้

รายละเอียดสำหรับการเก็บ debug log
0: no logging
1: errors (intercepted requests) only
2: warnings
3: notices
4: details of how transactions are handled
5: as above, but including information about each piece of information handled
9: log everything, including very detailed debugging information

ส่วนนี้เราจะกำหนดค่าคงไว้ที่ค่าเริ่มต้น

SecDebugLogLevel 0

ติดตั้ง package เพิ่มเติม ซึ่งเป็นส่วน base rules จาก mod_security crs (Core Rule Set)

[somchai@site2 ~]$ sudo yum install mod_security_crs.noarch

เมื่อติดตั้งเรียบร้อย จะพบว่ามีไฟล์ rule ต่างๆ อยู่ตาม path ด้านล่าง

/usr/lib/modsecurity.d/base_rules/

และมีการทำ symlinks มายัง path ตั้งต้น ของ modsecurity

/etc/httpd/modsecurity.d
/etc/httpd/modsecurity.d/activated_rules

หลังจากได้ rule ต่างๆ แล้วต่อไปเราจะเริ่มทดสอบใช้งาน

ทดสอบ sql injection rule

ซึ่งเบื้องต้นเราจะเลือกทดสอบใช้งานเฉพาะบางตัวก่อน ในที่นี่เราจะทดสอบ sql injection เท่านั้น โดยเริ่มแก้ไขดังนี้

[somchai@site2 ~]$ sudo vi /etc/httpd/conf.d/mod_security.conf
..แก้ไขจาก
IncludeOptional modsecurity.d/*.conf
IncludeOptional modsecurity.d/activated_rules/*.conf
..เปลี่ยนค่าเป็น
#IncludeOptional modsecurity.d/*.conf
#IncludeOptional modsecurity.d/activated_rules/*.conf
IncludeOptional modsecurity.d/activated_rules/modsecurity_crs_41_sql_injection_attacks.conf

save ไฟล์และสั่ง load config

[somchai@site2 ~]$ sudo systemctl reload httpd.service

login เข้าสู่ mysql

[somchai@site2 ~]$ sudo mysql -u root -p

เมื่อสามารถ login ผ่านจะพบ prompt MariaDB [(none)]> ให้ run คำสั่งตามด้านล่าง

MariaDB [(none)]> create database member;
MariaDB [(none)]> connect member;
MariaDB [(none)]> create table accounts(username VARCHAR(100),password VARCHAR(100));
MariaDB [(none)]> insert into accounts values('sompong','February');
MariaDB [(none)]> insert into accounts values('somsri','March');
MariaDB [(none)]> quit;

ทดสอบสร้างไฟล์ php เพื่อทดสอบเรียกใช้งาน

[somchai@site2 ~]$ sudo vi /var/www/html/login.php
<html>
<body>

<?php
if(isset($_POST['submit'])) {
<p style="padding-left: 30px;">$username = $_POST['username'];
$password = $_POST['password'];</p>
<p style="padding-left: 30px;">$con = mysqli_connect('localhost','root','
[YOUR PASSWORD]','members');</p>
<p style="padding-left: 30px;">$result = mysqli_query($con, "SELECT * FROM
 `accounts` WHERE username='$username' AND password='$password'");</p>
<p style="padding-left: 30px;">if(mysqli_num_rows($result) == 0) echo '<BR><h2>
You have entered an invalid username or password. </h2>';</p>
<p style="padding-left: 30px;">else echo '<br><h1>Signed in</h1><p>Hello!! '.$username.
'</p>';</p>
} else {
<p style="padding-left: 30px;">?>
<form action="" method="post">
<br/>
<h1>Member</h1>
Username: <input type="text" name="username"/><br/><br/>
Password: <input type="password" name="password"/><br/><br/>
<input type="submit" name="submit" value="Sign in"/>
</form>
<?php</p>
}
<span style="line-height: 1.5;">?>

ทดสอบใช้งานการ Sign in โดยทดสอบใส่ค่าที่ถูกต้อง และไม่ถูกต้องเพื่อตรวจสอบการทำงานและการติดต่อ database
http://site2.example.com/login.php
Username: somsri
Password: March

หลังจากนั้นให้ลองทดสอบใส่ค่า password ดังตัวอย่างด้านล่าง

‘ คือ Single quotes
true – – คือ SPACE true SPACE DASH SPACE DASH SPACE
select * from mysql; คือ select SPACE STAR from SPACE mysql SEMICOLON

และตรวจสอบการทำงานของ ModSecurity จากไฟล์ log
/var/log/httpd/modsec_audit.log
/var/log/httpd/error_log

ตัวอย่าง เช่น

[Thu Feb 12 11:42:04.076964 2015] [:error] [pid 25324] [client 192.168.0.12] ModSecurity: 
Warning. Pattern match "(/\\\\*!?|\\\\*/|[';]--|--[\\\\s\\\\r\\\\n\\\\v\\\\f]|(?:--[^-]*?-)
|([^\\\\-&])#.*?[\\\\s\\\\r\\\\n\\\\v\\\\f]|;?\\\\x00)" at ARGS:password. [file "/etc/httpd
odsecurity.d/activated_rules/modsecurity_crs_41_sql_injection_attacks.conf"] [line "49"] 
[id "981231"] [rev "2"] [msg "SQL Comment Sequence Detected."] [data "Matched Data: 
-- found within ARGS:password: true -- "] [severity "CRITICAL"] [ver "OWASP_CRS/2.2.6"] 
[maturity "8"] [accuracy "8"] [tag "OWASP_CRS/WEB_ATTACK/SQL_INJECTION"] 
[tag "WASCTC/WASC-19"] 
[tag "OWASP_TOP_10/A1"] [tag "OWASP_AppSensor/CIE1"] [tag "PCI/6.5.2"] 
hostname "site2.example.com"] [uri "/login.php"] [unique_id "VOVpnGfJ3dFwzEZxC4Wx8wAAAAM"]

ทดสอบสร้าง Rule เพื่อใช้งาน

เริ่มต้นจาก Rule แรก จะเป็นการปิดกั้นการใช้งานสำหรับ IP 192.168.0.12

[somchai@site2 ~]$ sudo vi /etc/httpd/conf.d/mod_security.conf
..เพิ่ม config ตามด้านล่าง
SecRule REMOTE_ADDR "^192.168.0.12$" "id:'5001',log,auditlog,deny,msg:'Test Rule'"

save ไฟล์และสั่ง load config

[somchai@site2 ~]$ sudo systemctl reload httpd.service

ทดสอบเรียกใช้งาน web จาก IP 192.168.0.12 หากไม่สามารถใช้งานได้ ให้ตรวจสอบเพิ่มเติมที่ไฟล์ log
[Thu Feb 12 14:44:18.166166 2015] [:error] [pid 26980] [client 192.168.0.12] ModSecurity: Access denied with code 403 (phase 2). Pattern match “^192.168.0.12$” at REMOTE_ADDR. [file “/etc/httpd/conf.d/mod_security.conf”] [line “56”] [id “5001”] [msg “Test Rule”] [hostname “site2.example.com”] [uri “/login.php”] [unique_id “VOWU5Km6ppso-fMuh0vBRQAAAAM”]

และสำหรับ Rule ที่จะแนะนำเพิ่มเติม จะเป็นการปิดกั้นการเรียกใช้งาน URL เมื่อมีการเรียก ค่า httpd.conf หรือ passwd

[somchai@site2 ~]$ sudo vi /etc/httpd/conf.d/mod_security.conf
..เพิ่ม config ตามด้านล่าง
SecRule REQUEST_URI "(?:\b(?:passwd|httpd\.conf)\b)" "id:'5002'deny,log,msg:
'Remote File Access Attempt'"

save ไฟล์และสั่ง load config

[somchai@site2 ~]$ sudo systemctl reload httpd.service

ทดสอบเรียกใช้งาน web จาก http://site2.example.com/login.php?passwd หากไม่สามารถใช้งานได้ ให้ตรวจสอบเพิ่มเติมที่ไฟล์ log

[Thu Feb 12 15:34:32.568072 2015] [:error] [pid 27134] [client 192.168.0.12] ModSecurity: Access denied with code 403 (phase 2). Pattern match “(?:\\\\b(?:passwd|httpd\\\\.conf)\\\\b)” at REQUEST_URI. [file “/etc/httpd/conf.d/mod_security.conf”] [line “58”] [id “5002”] [msg “Remote File Access Attempt”] [hostname “site2.example.com”] [uri “/login.php”] [unique_id “VOWgGIPP4q@AnEElri7AUgAAAAA”]

และหากต้องการ disable การใช้งานเฉพาะ บาง VirtualHost สามารถ เพิ่มค่าตามด้านล่าง เข้าไปยัง <VirtualHost> นั้นๆ

<VirtualHost>
…
<IfModule mod_security2.c>
SecRuleEngine Off
</IfModule>
...
</VirtualHost>

ข้อมูลเพิ่มเติมสำหรับ ModSecurity : https://github.com/SpiderLabs/ModSecurity/wiki/Reference-Manual

บริการ Virtual machine ต่างๆ ของ HostPacific เช่น CloudNode (เริ่มต้นเพียงชม.ละ 0.75 บาท), CloudNode-M (เริ่มต้นเพียงเดือนละ 450 บาท) หรือ Enterprise Cloud Server (เริ่มต้นเดือนละ 900 บาท) สามารถใช้งาน LAMP stack เช่นในบทความนี้ได้ทุกแพลน