2.2.2.1. Cài đặt môi trường.
Do yêu cầu về chịu tải cũng như việc tương thích với mã nguồn của openresty nên môi trường dùng để chạy hệ thống chống tấn công từ chối dịch vụ sẽ là linux. Sau khi tham khảo rất nhiều phiên bản linux khác nhau tác giả chọn phiên bản centos 6 là một phiên bản được dùng rộng rãi và rất ổn định trong thời điểm hiện tại. Centos được hỗ trợ từ cộng đồng rất lớn và được chạy trên nhiều hệ thống lớn nên khi đưa hệ thống ra chạy thực tế sẽ không gặp phải các lỗi không lường
trước được. Thêm vào đó centos các thư viện gần như đã có sẵn lên sẽ không mất thời gian cho việc cài đặt thư viện cũng như các thành phần cần thiết. Như đã nói ở trên hệ thống sẽ được xây dựng trên nền openresty và ngôn ngữ để lập trình sẽ là lua.
Cài đặt openresty:
#cài đặt repo của epel
rpm -ivh https://dl.fedoraproject.org/pub/epel/6/x86_64/epel-release-6-8.noarch.rpm
#cập nhật gói yum update
#cài đặt các gói cần thiết để biên dịch
yum install readline-devel pcre-devel openssl-devel gcc perl wget #download openresty wget https://openresty.org/download/openresty-1.11.2.1.tar.gz #giải nén và biên dịch tar -xvf openresty-1.11.2.1.tar.gz cd openresty-1.11.2.1 ./configure make make install
#openresty được cài vào thư mục /usr/local/openresty
Cài đặt các thư viện lua cần thiết để phát triển hệ thống:
#cài dặt gói cần thiết
yum install git lua-devel unzip #cài đặt luarocks
git clone git://github.com/keplerproject/luarocks.git ./configure
make build make install
#cài đặt các gói cần thiết cho các module
luarocks install luasec OPENSSL_LIBDIR=/usr/lib64/ luarocks install lua-cjson
luarocks install luasocket
#các thư viện sẽ dược cài vào thư mục /usr/local/lib/lua/5.1 #lấy các thư viện cần thiết để phát triển
git clone https://github.com/openresty/lua-resty-limit-traffic
git clone https://github.com/openresty/lua-resty-cookie
git clone https://github.com/openresty/lua-resty-string
git clone https://github.com/hamishforbes/lua-resty-iputils
2.2.2.2. Module tạo cookie xác thực.
Phần quan trọng nhất của module xác thực người dùng là phần tạo cookie xác thực như các yêu cầu đã nói ở phần 2.1.1. Phần cookie xác thực người dùng trong hệ thống sẽ được xây dựng bằng cách:
Bước 1: lấy thời gian hiện tại của hệ thống sau đó chia lấy phần nguyên với một khoảng thời gian xác định gọi là thời gian hợp lệ của cookie.
Bước 2: lấy các giá trị đặc trưng của người dùng ở đây là địa chỉ ip và useragent của request.
Bước 3: Cộng một chuỗi secret mà chỉ server mới có với hai thông tin lấy được ở bước 1 và bước 2 sau đó dùng mã hoá băm với dữ liệu này. Cookie authen cuối cùng sẽ là một chuỗi có độ dài bằng độ dài của thuật toán băm tương ứng. Thuật toán này được triển ra ra code như sau.
local current_time = os.time()
local authen_data = ngx.var.remote_addr .. useragent
local secret = authen_data .. current_time - (current_time % cookie_windows) local sha256 = resty_sha256:new()
sha256:update(key) sha256:update(secret)
local digest = str.to_hex(sha256:final())
Phần này dùng thư viện lua-resty-string của openresty. Trong đó key là chuỗi bí mật chỉ có server có. Cookie xác thực này có những đặc điểm phù hợp với yêu cầu đã được trình bày như:
- Gần như không thể giả được cookie xác thực trừ khi biết được chuỗi bít mật của server.
- Do dùng mã hoá băm nên người tấn công cũng khó có thể đoán được các yếu tố nào dùng để xác thực.
- Cookie chỉ được xác thực trong một khoảng thời gian xác định nên tránh được việc người tấn công dùng mã giả trình duyệt để lấy cookie sau đó dùng cookie này cho các request tấn công từ chối dịch vụ sau.
- Mã hoá băm sha256 có mức độ an toàn tương đối tốt và thời gian chạy cũng như tài nguyên yêu cầu tương đối thấp nên rất hợp cho một hệ thống chống tấn công từ chối dịch vụ như này.
Xác thực tính chính xác của cookie xác thực của người dùng có:
Phần này rất đơn giản là chỉ lấy cookie xác thực của người dùng nếu có sau đó so sánh với cookie xác thực mà server tạo ra cho người dùng. Phần này được viết dùng thư viện lua-resty-cookie của openresty với mã như sau:
--- lấy cookie xác thực, nếu không có thì cookie sẽ có giá trị là nil ( None hoặc rỗng)
local ck = require "resty.cookie" local cookie, err = ck:new() if not cookie then
ngx.log(ngx.ERR, err) return ngx.exit(500) end
local ecofair_cookie, err = cookie:get(ecofair_cookie_name) --- xác thực xem cookie có chính xác không
if (not ecofair_cookie or not(ecofair_cookie == digest)) then … tạo cookie xác thực cho người dùng với module thích hợp
2.2.2.3. Module xác thực người dùng bằng javascript.
Module này làm tương đối đơn giản do yêu cầu cần chạy được với tất cả các trình duyệt phổ biến và người dùng dùng. Chức năng của module rất đơn giản là tạo cookie cho người dùng và yêu cầu trình duyệt tải lại trang web với đường dẫn đang xem. Phần này được triển khai ở mực rất đơn giản và sẽ được phát triển trong tương lai với nhiều tính năng hơn như xác thực browser dựa vào javascript, dùng một số kỹ thuật javascript để phát hiện website đang được tải bời các công cụ bô phỏng trình duyệt access_list:incr(authen_data, 1) ngx.say(string.format("<html><body><script> document.cookie=\"%s=%s\";window.location.reload(true);</script></body></html >", ecofair_cookie_name, digest)) ngx.exit(ngx.HTTP_OK) với mã rất đơn giản là
<html><body><script>document.cookie="Cookie xác thực";window.location.reload(true);</script></body></html>
document.cookie="Cookie xác thực"; là phần tạo cookie cho người dùng và window.location.reload(true); để trình duyệt tự tải lại trang.
2.2.2.4. Module xác thực bằng captcha.
Module này được triển khai dùng dịch vụ recaptcha của google để tạo tính đơn giản. Trong phần này xử dụng hai thư viện của lua để viết lại phần xác thực captcha với phía server của người dùng là lua-cjson và luasec. Phần tạo captcha cho người dùng rất đơn giản bằng mã html như sau:
<html> <head>
<title>Ecofair</title>
<script src="https://www.google.com/recaptcha/api.js" async defer></script> </head>
<body>
<form action="/cgi-bin/ecofair-captcha" method="GET"> <div class="g-recaptcha" data-sitekey="site’s key"></div> <br/>
<input type="submit" value="Submit">
</form> </body> </html>
Trong đó site’s key là mã được google cung cấp cho người dùng khi đăng ký dịch vụ recaptcha của google.
Module xác thực này do dùng version mới hơn của recaptcha và chưa có thư viện nào của lua thực hiện xác thực với google nên tác giả tự viết phần xác thực với phía server của google xem phần captcha nhập vào có hợp lệ không.
function verify_captcha(g_recaptcha_response) local https = require 'ssl.https'
local cjson = require 'cjson'
--- -- https://www.google.com/recaptcha/api/siteverify
-- secret Required. The shared key between your site and ReCAPTCHA.
-- response Required. The user response token provided by the reCAPTCHA to the user and provided to your site on.
-- remoteip Optional. The user's IP address.
---
local recaptcha_url = "https://www.google.com/recaptcha/api/siteverify" local body, code, headers, status = https.request(recaptcha_url, "secret=" .. recaptcha_secret .. "&response=" .. g_recaptcha_response)
local data = cjson.decode(body)
--- -- {
-- "success": true|false,
-- "challenge_ts": timestamp, // timestamp of the challenge load (ISO format yyyy-MM-dd'T'HH:mm:ssZZ)
-- "hostname": string, // the hostname of the site where the reCAPTCHA was solved -- "error-codes": [...] // optional -- } --- if (data['success']) then return true end return false end 30
Khi người dùng giải thành công captcha và submit lại lên thì sẽ tạo cookie xác thực cho người dùng thông qua header của kết quả trả về dùng module lua-resty-cookie của openresty.
local ok, err = cookie:set({
key = ecofair_cookie_name, value = digest })
2.2.2.5. Module xác thực bot của các công cụ tìm kiếm.
Như đã nói ở chương 1 có 2 cách xác thực bot của công cụ tìm kiếm khác nhau. Tuy vào khi nghiên cứu các yêu cầu đối với trang thương mại điện tử cũng như các công cụ tìm kiếm phổ biến nhất thì các công cụ hay được người dùng dùng nhất là google, bing của microsoft và củ facebook. Do đó phòng phần này triển khai thuật toán xác thực bot tìm kiếm bằng dns và áp dụng với 2 công cụ tìm kiếm là google và bing và xác thực bằng ip với facebook. Module xác thực qua dns dùng thư viện luasocket của lua và được cài đặt thông qua luarocks. Module xác thực qua ip dùng module lua-resty-iputils. Với code rất đơn giản như sau:
Xác thực googlebot
if ngx.re.match(useragent, "googlebot", "i") then -- ngx.say("googlebot")
local socket = require('socket')
google_hostname = socket.dns.tohostname(ngx.var.remote_addr) -- test --
-- google_hostname = socket.dns.tohostname("66.249.66.1") -- ngx.say(google_hostname)
-- test --
if (not google_hostname or not ngx.re.match(google_hostname, "googlebot.com")) then ngx.exit(ngx.HTTP_FORBIDDEN) -- captcha authen end return end Xác thực bingbot --- -- bing's bot authentication --
-- https://udger.com/resources/ua-list/bot-detail?bot=bingbot ---
if ngx.re.match(useragent, "http://www.bing.com/bingbot.htm") then local socket = require("socket")
---
-- https://www.bing.com/webmaster/help/which-crawlers-does-bing-use- 8c184ec0
---
bing_hostname = socket.dns.tohostname(ngx.var.remote_addr)
if (not bing_hostname or not ngx.re.match(bing_hostname, "search.msn.com")) then ngx.exit(ngx.HTTP_FORBIDDEN) end return end Xác thực facebookbot
local iputils = require("resty.iputils") iputils.enable_lrucache() --
local facebook_ips = { … facebook’s ip ranges … }
if ngx.re.match(useragent, "facebookexternalhit") or ngx.re.match(useragent, "Facebot") then
local iputils = require("resty.iputils")
if not iputils.ip_in_cidrs(ngx.var.remote_addr, facebook_whitelist) then return ngx.exit(ngx.HTTP_FORBIDDEN)
end return end
Khi bot không được xác thực sẽ trả lại người dùng cấm truy cập và dừng không cho request vào website nữa.
2.2.2.6. Module giới hạn số request của người dùng.
Như đã nói để hạn chế việc người tấn công dùng cách tạo cookie xác thực rồi dùng cookie đó để tấn công tiếp và thông thường khi tấn công từ chối dịch vụ thì người tấn công thường phải tạo số request nhiều nhất có thể. Thêm vào đó người dùng bình thường thường không tạo quá nhiều request trong một khoảng thời gian ngắn. Module này được xây dựng dựa trên thư viện lua-resty-limit-traffic của
openresty. Khi người dùng vượt quá giới hạn đặt ra thì bắt buộc phải bị xác thực bằng captcha.
local limit_req = require "resty.limit.req"
local lim, err = limit_req.new("ecofair_limit_req", 40, 10) if not lim then
ngx.log(ngx.ERR, "failed to instantiate a resty.limit.req object: ", err) return ngx.exit(500)
end
local key = ngx.var.binary_remote_addr .. useragent local delay, err = lim:incoming(key, true)
if not delay then
if err == "rejected" then
local authen_data = ngx.var.remote_addr .. useragent access_list:safe_set(authen_data, 6)
else
ngx.log(ngx.ERR, "failed to limit req: ", err) return ngx.exit(500)
end end
2.2.3. Triển khai hệ thống thực tế.
Hệ thống được triển khai dựa trên openresty bằng cách cấu hình openresty cho phù hợp với yêu cầu. Các files cấu hình và mã nguồn được thêm vào như sau:
nginx.conf: file cấu hình chung của openresty như khi request được cho phép thì sẽ chuyển đến đâu, cần tải các thành phần hay thư viện nào để chạy code.
captcha.html: file chứa phần mã để hiện captcha cho người dùng, có thể sửa đổi theo ý muốn.
init.lua: file mã nguồn chứa tất cả các tham số khởi tạo cũng như các function dùng chung cho toàn bộ hệ thống.
ecofair.lua: phần xử lý logic chính của hệ thống chứa gần như tất cả các module cũng như thể hiện logic như đã viết ở phần 2.1.2.
recaptcha.lua: xác thực captcha người dùng, tạo captcha khi thành công. File cấu hình của nginx như sau:
#user nobody; worker_processes 2; events { worker_connections 2048; } http { include mime.types; default_type application/octet-stream;
log_format main '$remote_addr - $remote_user [$time_local] "$request" ' '$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"'; access_log logs/access.log main;
sendfile on; #tcp_nopush on; #keepalive_timeout 0; keepalive_timeout 65; #gzip on;
#lua_code_cache off; # DEBUG only
# dùng cho phần limit request và quản lý xác thực. lua_shared_dict ecofair_limit_req 100m; lua_shared_dict ecofair_accesslist 50m; lua_package_cpath "/usr/local/lib/lua/5.1/?.so;/usr/local/lib/lua/5.1/socket/?.so;/usr/local/lib/lua/5.1/mi me/?.so;;"; lua_package_path "/usr/local/share/lua/5.1/ssl/?.lua;/usr/local/share/lua/5.1/?.lua;/ecofair/lua-resty- cookie/lib/?.lua;/ecofair/lua-resty-string/lib/?.lua;/ecofair/lua-resty-limit- traffic/lib/?.lua; /ecofair/lua-resty-iputils/lib/?.lua;;"; init_by_lua_file '/ecofair/init.lua'; server { listen 80; server_name localhost; 34
#charset koi8-r;
location /cgi-bin/ecofair-captcha { default_type 'text/html';
access_by_lua_file '/ecofair/recaptcha.lua'; }
#access_log logs/host.access.log main; location / {
default_type 'text/html';
access_by_lua_file '/ecofair/ecofair.lua';
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header Host $host;
proxy_pass http://websiteip; } error_page 500 502 503 504 /50x.html; location = /50x.html { root html; } } }
Các thành phần code của các file lua đã được trình bày ở các phần trên.
CHƯƠNG 3: TRIỂN KHAI, THỬ NGHIỆM HỆ THỐNG.
3.1. Mô hình và quy mô triển khai thử nghiệm của hệ thống.
Do điều kiện thử nghiệm hệ thống trong điều kiện thực tế khá khó để thực hiện. Vì khi hệ thống đang chạy trong thực tế việc thử nghiệm tấn công vào hệ thống có thể dẫn đến nhiều vấn đề không lường trước được. Hoặc nếu chỉ theo dõi để xác thực hệ thống chạy tốt khi có tấn công từ chối dịch vụ thì khả năng trong thời gian chạy thử nghiệm trang web được thử nghiệm bị tấn công là không cao. Vì vậy để thử nghiệm hệ thống trong khôn khổ đồ án này hệ thống được thử nghiệm sẽ là một trang web được dựng bằng mã nguồn phổ biến mà các trang thương mại điện tử hay dùng. Khi thử nghiệm website sẽ bị tấn công bằng cách công cụ tấn công từ chối dịch vụ phổ biến và dễ thực hiện trên mạng cộng với một số mã tự viết có phần