Author: mr.linhnh5

  • Tối ưu Nginx & PHP-fpm cho lượng truy cập lớn

    Tối ưu Nginx & PHP-fpm cho lượng truy cập lớn

    PHP hiện tại là ngôn ngữ được triển khai rộng rãi trên Internet.

    Tuy nhiên PHP lại hay được nhìn nhận là 1 ngôn ngữ có khả năng hiệu suất (performance) kém, do đó khi các website, api có lượng truy cập lớn lại nghĩ tới sử dụng các ngôn ngữ khác như Nodejs, Golang…

    Mặc dù vậy chúng ta vẫn có thể cải thiện điều này. Bài viết này sẽ hướng dẫn các bạn 1 số cách cải thiện tốc độ xử lý của PHP, cụ thể là PHP-fpm trên server Nginx.

    PHP-fpm là gì?

    Không phải tất cả Developer đều quan tâm tới tất cả các khía cạnh của DevOps, và trong số đó không phải ai cũng hiểu cách server xử lý trong 1 thời gian ngắn. Một điều thú vị là khi có 1 request tới server PHP thì không phải PHP xử lý nó trực tiếp mà là các máy chủ (Nginx / Apache), sau đó các máy chủ này mới quyết định truyền dữ liệu, type, header tới PHP.

    Trong các ứng dụng sử dụng PHP hiện tại, thì phần lớn file index được cấu hình là index.php, file sẽ nhận mọi request từ server tới. Bây giờ thì chính xác server đã gọi tới các file php như thế nào? Nếu tìm hiểu vấn đề này sâu xa thì tất mất thời gian, do đó ở bài này chúng ta chỉ tìm hiểu 1 cách sơ lược thôi. Đại khái trong giai đoạn mà web server Apache thống trị thì PHP là 1 module trong đó. Khi mà mỗi request được gửi tới server, server sẽ tiến hành xử lý 1 tiến trình (process), process này sẽ bao gồm xử lý php. Phương thức này sẽ gọi mod_php trong Apache, như vậy php là 1 module. Cách tiếp cận này có các hạn chế nhất định, điều mà Nginx đã giải quyết với php-fpm.

    Đối với php-fpm thì trách nhiệm quản lý cũng như các quy trình xử lý đều nằm trong chương trình PHP trong server. Nói 1 cách khác là web server (cụ thể là Nginx) sẽ ko quan tâm file PHP ở đâu, nó được load như thế nào nếu như biết cách gửi và nhận data từ nó. Nếu như bạn muốn, bạn có thể coi PHP trong trường hợp này như là 1 server khác và nó sẽ quản lý các tiến trình php trong các request được gửi tới.

    Nếu như bạn đã setup server Nginx, bạn sẽ thấy các cấu hình như sau:

    location ~ \.php$ {

    try_files $uri =404;

    fastcgi_split_path_info ^(.+\.php)(/.+)$;

    fastcgi_pass unix:/run/php/php7.2-fpm.sock;

    fastcgi_index index.php;

    include fastcgi_params;       

    fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;

    }

    Chú ý dòng fastcgi_pass unix:/run/php/php7.2-fpm.sock; Cấu hình này chỉ ra cho Nginx sẽ kết nối tới tiến trình PHP thông qua socket có tên là php7.2-fpm.sock . Do đó tất cả các request Nginx gửi data tới file này và nhận output sau đó trả về cho browser.

    Tóm lại điều chúng ta cần nắm được ở đây là

    • PHP không trực tiếp nhận các request từ trình duyệt, các web server (Nginx) sẽ chặn chúng
    • Các web server biết cách kết nối tới các tiến trình PHP và gửi các dữ liệu tới chúng.
    • Sau khi các tiến trình PHP xử lý xong chúng sẽ trả output về các web server, web server sẽ trả lại các client

    Vậy cuối cùng PHP-FPM là cái gì?

    FPM là viết tắt của “Fast Process Manager” điều này có nghĩa là PHP chạy trên server không phải là một tiến trình đơn lẻ, mà nó bao gồm nhiều tiến trình được sinh ra, điều khiển, tắt bới trình quản lý fpm. Nó chính là trình quản lý mà web server sẽ gửi các request tới.

    Tại sao phải tối ưu php-fpm?

    Nếu server của bạn vẫn đang đáp ứng tốt nhu cầu sử dụng, cũng như đang ổn định thì tất nhiên không việc gì phải tối ưu nó cả. Tuy nhiên trong trường hợp server của bạn đang không đáp ứng đủ nhu cầu, cũng như lượng server của bạn bị hạn chế thì việc tối ưu từng server lại là điều cần thiết.

    Một khía cạnh khác là Nginx được xây dựng để xử lý 1 số lượng công việc khổng lồ, nó có thể đáp ứng hàng nghìn kết nối, và thật lãng phí nếu như bạn không sử dụng hết sức mạnh của nó để tối ưu tài nguyên vì Nginx sẽ phải chờ tiến trình PHP hiện tại xử lý xong mới xử lý tới request tiếp theo, điều này không đúng với những ưu điểm mà Nginx được tạo ra.

    Vậy tối ưu php-fpm như thế nào?

    File cấu hình của php-fpm ở các server có thể sẽ khác nhau, với ubuntu thì nó được để tại /etc/php/7.2/fpm/php-fpm.conf (Đây là đường dẫn của php version 7.2)

    Một vài config ban đầu bạn có thể thấy

     ;;;;;;;;;;;;;;;;;;;;;
    ; FPM Configuration ;
    ;;;;;;;;;;;;;;;;;;;;;
    
    ; All relative paths in this configuration file are relative to PHP's install
    ; prefix (/usr). This prefix can be dynamically changed by using the
    ; '-p' argument from the command line.
    
    ;;;;;;;;;;;;;;;;;;
    ; Global Options ;
    ;;;;;;;;;;;;;;;;;;
    
     [global] 
    ; Pid file 
    ; Note: the default prefix is /var 
    ; Default Value: none 
    pid = /run/php/php7.2-fpm.pid 
    ; Error log file 
    ; If it's set to "syslog", log is sent to syslogd instead of being written 
    ; into a local file. 
    ; Note: the default prefix is /var 
    ; Default Value: log/php-fpm.log 
    error_log = /var/log/php7.2-fpm.log 

    Một vài điểm cần chú ý trong cấu hình trên:

    pid = /run/php/php7.2-fpm.pid 

    Cấu hình này chỉ ra file chứa process id của tiến trình php-fpm

    error_log = /var/log/php7.2-fpm.log

    Còn đây là cấu hình file mà php sẽ ghi log.

    Bên cạnh đó còn 3 cấu hình

    emergency_restart_threshold 10
    emergency_restart_interval 1m
    process_control_timeout 10s

    Hai dòng đầu chỉ ra rằng nếu 10 quy trình con không thành công trong vòng 1 phút thì php-fpm sẽ tự động khởi động lại. Điều này nghe có vẻ “yếu” nhưng thực ra PHP là một tiến trình ngắn, nó làm tốn dữ liệu vì vậy việc khởi động lại trong trường hợp lỗi sẽ giải quyết được nhiều vấn đề. Cấu hình thứ 3 là thời gian các tiến trình con chờ đợi tín hiệu từ tiến trình cha .

    Thực ra bên trên vẫn chưa phải là cấu hình chính của php-fpm. Bởi vì để phục vụ các request từ server, php-fpm tạo ra một pool mới để quản lý các tiến trình, và nó sẽ có các cấu hình khác nhau. Ví dụ 1 pool có tên là www. File config là: /etc/php/7.2/fpm/pool.d/www.conf

    ; Start a new pool named 'www'. 
    ; the variable $pool can be used in any directive and will be replaced by the 
    ; pool name ('www' here) 
    [www] 
    ; Per pool prefix 
    ; It only applies on the following directives: 
    ; - 'access.log' 
    ; - 'slowlog' 
    ; - 'listen' (unixsocket) 
    ; - 'chroot' 
    ; - 'chdir' 
    ; - 'php_values' 
    ; - 'php_admin_values' 
    ; When not set, the global prefix (or /usr) applies instead. 
    ; Note: This directive can also be relative to the global prefix. 
    ; Default Value: none 
    ;prefix = /path/to/pools/$pool 
    ; Unix user/group of processes 
    ; Note: The user is mandatory. If the group is not set, the default user's group 
    ;       will be used. 
    user = www-data 
    group = www-data  

    Cấu hình mặc định thường như sau:

    pm = dynamic
    pm.max_children = 5
    pm.start_servers = 3
    pm.min_spare_servers = 2
    pm.max_spare_servers = 4
    pm.max_requests = 200

    Chú ý “dynamic” ở đây có ý nghĩa như thế nào. Xem các option có thể setting:

    ; Choose how the process manager will control the number of child processes.
    ; Possible Values:
    ;   static  - a fixed number (pm.max_children) of child processes;
    ;   dynamic - the number of child processes are set dynamically based on the
    ;             following directives. With this process management, there will be
    ;             always at least 1 children.
    ;             pm.max_children      - the maximum number of children that can
    ;                                    be alive at the same time.
    ;             pm.start_servers     - the number of children created on startup.
    ;             pm.min_spare_servers - the minimum number of children in 'idle'
    ;                                    state (waiting to process). If the number
    ;                                    of 'idle' processes is less than this
    ;                                    number then some children will be created.
    ;             pm.max_spare_servers - the maximum number of children in 'idle'
    ;                                    state (waiting to process). If the number
    ;                                    of 'idle' processes is greater than this
    ;                                    number then some children will be killed.
    ;  ondemand - no children are created at startup. Children will be forked when
    ;             new requests will connect. The following parameter are used:
    ;             pm.max_children           - the maximum number of children that
    ;                                         can be alive at the same time.
    ;             pm.process_idle_timeout   - The number of seconds after which
    ;                                         an idle process will be killed.
    ; Note: This value is mandatory.

    Giải thích sơ lược thì như sau

    pm.max_children = Số process con (child processes) tối đa được tạo (tương đương tổng số request có thể phục vụ)
    pm.start_servers = Tổng số child processes được tạo khi khởi động php-fpm (được tính bằng công thức `min_spare_servers + (max_spare_servers – min_spare_servers) / 2` )
    pm.min_spare_servers = Tổng số child process nhàn rỗi tối thiểu được duy trì.
    pm.max_spare_servers = Tổng số child process nhàn rỗi tối đa được duy trì.

    Chúng ta có các option sau:

    • Static: fix cứng 1 số lượng process được duy trì
    • Dynamix: set số lượng min và max các process có thể được duy trì ở bất cứ thời điểm nào
    • ondemand: Các process sẽ được tạo ra và tắt đi theo yêu cầu

    Vậy các con số này có ý nghĩa như thế nào? Nếu như web server của bạn có lượng truy cập rất ít thì việc chọn cấu hình là dynamic sẽ rất phí tài nguyên, trong trường hợp này bạn có thể set pm.min_spare_servers = 3 và chọn option “ondemand” để server quyết định số lượng process.

    Trong trường hợp ngược lại với 1 web site có số lượng truy cập lớn, thì nên setting về static, và setting với số lượng tối đa mà server có thể sử dụng.

    Cách tính pm.max_children

    B1. Xác định số lượng bộ nhớ cần thiết trung bình cho 1 process php-fpm

    ps -ylC php-fpm --sort:rss

    Ouput sẽ tương tự như sau, column RSS sẽ chứa giá trị mà chúng ta cần xác định

    S UID PID PPID C PRI NI RSS SZ WCHAN TTY TIME CMD
    S 0 24439 1 0 80 0 6364 57236 - ? 00:00:00 php-fpm
    S 33 24701 24439 2 80 0 61588 63335 - ? 00:04:07 php-fpm
    S 33 25319 24439 2 80 0 61620 63314 - ? 00:02:35 php-fpm

    Như kết quả ở trên là khoảng 61620KB, tương đương với ~60MB/process
    B2: Tính toán ra pm.max_children

    Ví dụ server hiện tại có khoảng 4GB RAM, đang chạy cả web và DB, chúng ta sẽ tính con số ước lượng là DB hoạt động khoảng 1GB và 0.5G dành cho buffer. Với các con số như vậy thì dung lượng RAM còn lại cho hoạt động của php-fpm tương đương với: 4 – 1 – 0,5 = 2,5 GB RAM hoặc 2560 Mb.

    pm.max_children = 2560 Mb / 60 Mb = 42

    Làm tròn con số xuống (để đảm bảo server hoạt động không bị quá tải), thì pm.max_children = 40
    Cách tính pm.min_spare_servers

    pm.min_spare_servers có giá trị tương đương với 20% của pm.max_children.
    Nếu như với gía trị ở trên thì pm.max_spare_servers = 60% * 40 = 24
    Cũng có hướng dẫn ghi là pm.max_spare_servers = (cpu cores) * 4
    Cách tính pm.max_requests

    Tham số này chính là số lượng request xử lý đồng thời mà server có thể chịu tải được, giá trị phụ thuộc vào pm.max_children và số lượng request trên 1s vào server. Con số này tính toán cũng khá hên xui, nhưng có thể có 1 phương pháp là sử dụng tool ab của apache sau đó giảm giá trị dần dần sao cho phù hợp.

    ab -n 5000 -c 100 http://domain.com/

    Khi chạy command trên thì có nghĩa là tạo ra 5000 request với 100 session hoạt động cùng lúc truy cập vào url http://domain.com. Giá trị pm.max_requests có thể set là 1000 sau đó tăng/giảm dần đến mức phù hợp (Phù hợp là khi server vẫn còn chịu được tải).

    Cấu hình Nginx để tăng performance

    Mở file /etc/nginx/nginx.conf và điều chỉnh theo các hướng dẫn sau.
    Trước hết bạn cần nắm công thức:

    max_clients = worker_processes * worker_connections
    số lượng người truy cập tối đa Nginx có thể phục vụ bằng thông số worker_processes nhân với worker_connections. Mặc định sau khi cài đặt Nginx thì

    worker_processes = 1

    worker_connections = 1024.

    Các bạn cần chỉnh lại worker_processes bằng với số lượng CPU core trong server bạn cấu hình. Có thể xem số CPU Core thông qua lệnh sau:

    cat /proc/cpuinfo |grep processor

    Với số lượng CPU bằng 4 bạn có thể setting worker_processes  = 4, như vậy lượng truy cập tối đa sẽ là 4 * 1024

    Để tăng thêm số lượng connection bạn cũng có thể thay đổi thêm

    worker_rlimit_nofile 2048;

    Cấu hình này giúp bạn có thể setting worker_connections  lên tới 2048

    Ngoài ra các bạn cũng cần thiết giới hạn kích thước body của các http request và buffer dùng xử lý http request thông qua việc thêm hai thông số sau đây vào file cấu hình

    client_max_body_size 20m;

    client_body_buffer_size 128k;

    Tăng tốc bằng cache file. Với các file tĩnh trên server thì chúng ta hoàn toàn có thể cache lại bằng config

    location ~* .(jpg|jpeg|gif|png|css|js|ico|xml)$ {
    access_log off;
    log_not_found off;
    expires 360d;
    }

    Anh em đọc tham khảo. Bài cóp nhặt từ nhiều nguồn, khá hữu ích cho các anh em PHP.

  • Top 10 lỗ hổng bảo mật web phổ biến theo chuẩn OWASP – OWASP TOP 10

    Top 10 lỗ hổng bảo mật web phổ biến theo chuẩn OWASP – OWASP TOP 10

    Dành cho ae lập trình web – Đọc qua mà né

    1. Lỗ hổng Injection (Lỗi chèn mã độc)

    Injection là lỗ hổng xảy ra do sự thiếu sót trong việc lọc các dữ liệu đầu vào không đáng tin cậy. Khi bạn truyền các dữ liệu chưa được lọc tới Database (Ví dụ như lỗ hổng SQL injection), tới trình duyệt (lỗ hổng XSS), tới máy chủ LDAP (lỗ hổng LDAP Injection) hoặc tới bất cứ vị trí nào khác. Vấn đề là kẻ tấn công có thể chèn các đoạn mã độc để gây ra lộ lọt dữ liệu và chiếm quyền kiểm soát trình duyệt của khách hàng.

    Mọi thông tin mà ứng dụng của bạn nhận được đều phải được lọc theo Whitelist. Bởi nếu bạn sử dụng Blacklist việc lọc thông tin sẽ rất dễ bị vượt qua (Bypass). Tính năng Pattern matching sẽ không hoạt động nếu thiết lập Blacklist.

    Cách ngăn chặn lỗ hổng:

    Để chống lại lỗ hổng này chỉ “đơn giản” là vấn đề bạn đã lọc đầu vào đúng cách chưa hay việc bạn cân nhắc  liệu một đầu vào có thể được tin cậy hay không. Về căn bản, tất cả các đầu vào đều phải được lọc và kiểm tra trừ trường hợp đầu vào đó chắc chắn đáng tin cậy.(Tuy nhiên việc cẩn thận kiểm tra tất cả các đầu vào là luôn luôn cần thiết).

    Ví dụ, trong một hệ thống với 1000 đầu vào, lọc thành công 999 đầu vào là không đủ vì điều này vẫn để lại một phần giống như “gót chân Asin”, có thể phá hoại hệ thống của bạn bất cứ lúc nào. Bạn có thể cho rằng đưa kết quả truy vấn SQL vào truy vấn khác là một ý tưởng hay vì cơ sở dữ liệu là đáng tin cậy. Nhưng thật không may vì đầu vào có thể gián tiếp đến từ những kẻ có ý đồ xấu. Đây được gọi là lỗi Second Order SQL Injection.

    Việc lọc dữ liệu khá khó vì thế các bạn nên sử dụng các chức năng lọc có sẵn trong framework của mình. Các tính năng này đã được chứng minh sẽ thực hiện việc kiểm tra một cách kỹ lưỡng. Bạn nên cân nhắc sử dụng các framework vì đây là một trong các cách hiệu quả để bảo vệ máy chủ của bạn.

    2. Broken Authentication

    Đây là nhóm các vấn đề có thể xảy ra trong quá trình xác thực. Có một lời khuyên là không nên tự phát triển các giải pháp mã hóa vì rất khó có thể làm được chính xác.

    Có rất nhiều rủi ro có thể gặp phải trong quá trình xác thực:

    • URL có thể chứa Session ID và rò rỉ nó trong Referer Header của người dùng khác.
    • Mật khẩu không được mã hóa hoặc dễ giải mã trong khi lưu trữ.
    • Lỗ hổng Session Fixation.
    • Tấn công Session Hijacking có thể xảy ra khi thời gian hét hạn của session không được triển khai đúng hoặc sử dụng HTTP (không bảo mật SSL)…

    Cách ngăn chặn lỗ hổng:

    Cách đơn giản nhất để tránh lỗ hổng bảo mật web này là sử dụng một framework. Trong trường hợp bạn muốn tự tạo ra bộ xác thực hoặc mã hóa cho riêng mình, hãy nghĩ đến những rủi ro mà bạn sẽ gặp phải và tự cân nhắc kĩ trước khi thực hiện.

    3. Lỗ hổng XSS (Cross Site Scripting)

    Sơ đồ quá trình tấn công XSS

    Lỗ hổng XSS (Cross-scite Scripting) là một lỗ hổng rất phổ biến. Kẻ tấn công chèn các đoạn mã JavaScript vào ứng dụng web. Khi đầu vào này không được lọc, chúng sẽ được thực thi mã độc trên trình duyệt của người dùng. Kẻ tấn công có thể lấy được cookie của người dùng trên hệ thông hoặc lừa người dùng đến các trang web độc hại.

    Cách ngăn chặn lỗ hổng:
    Có một cách bảo mật web đơn giản đó là không trả lại thẻ HTML cho người dùng. Điều này còn giúp chống lại HTML Injection – Một cuộc tấn công tương tự mà hacker tấn công vào nội dung HTML – không gây ảnh hưởng nghiêm trọng nhưng khá rắc rối cho người dùng. Thông thường cách giải quyết đơn giản chỉ là Encode (chuyển đổi vê dạng dữ liệu khác) tất cả các thẻ HTML. Ví dụ thẻ <script> được trả về dưới dạng <script&gt.

    4. Insecure Direct Object References

    Đây là trường hợp điển hình của việc cho rằng đầu vào của người dùng là tin cậy từ đó dẫn đến lỗ hổng bảo mật. Lỗ hổng này xảy ra khi chương trình cho phép người dùng truy cập các tài nguyên (dữ liệu, file, database). Nếu không thực hiện quá trình kiểm soát quyền hạn (hoặc quá trình này không hoàn chỉnh) kẻ tấn công có thể truy cập một cách bất hợp pháp vào các dữ liệu nhạy cảm, quan trọng trên máy chủ.

    Chúng ta có thể xem xét ví dụ sau:

    Một đoạn mã có module download.php và cho phép người dùng tải tệp xuống sử dụng tham số CGI. Ví dụ download.php?file=something.txt. Do sai sót của nhà phát triển, việc kiểm tra quyền hạn đã bị bỏ qua. Kẻ tấn công có thể sử dụng lỗ hổng này để tải về bất kì tệp nào trên hệ thống mà ứng dụng có quyền truy cập. Chẳng hạn như code ứng dụng, hoặc các dữ liệu khác trên máy chủ.

    Một ví dụ phổ biến khác là chức năng đặt lại mật khẩu dựa vào đầu vào của người dùng để xác định mật khẩu đặt lại. Sau khi nhấp vào URL hợp lệ, kẻ tấn công có thể sửa đổi trường tên người dùng trong URL để “đóng giả” admin.

    Cách ngăn chặn lỗ hổng: Thực hiện phân quyền người dùng đúng cách và nhất quán với sự áp dụng triệt để các Whitelist.

    5. Security Misconfiguration

    Trong thực tế, máy chủ website và các ứng dụng đa số bị cấu hình sai. Có lẽ do một vài sai sót như:

    • Chạy ứng dụng khi chế độ debug được bật.
    • Directory listing
    • Sử dụng phần mềm lỗi thời (WordPress plugin, PhpMyAdmin cũ)
    • Cài đặt các dịch vụ không cần thiết.
    • Không thay đổi default key hoặc mật khẩu
    • Trả về lỗi xử lý thông tin cho kẻ tấn công lợi dụng để tấn công, chẳng hạn như stack traces.

    Cách ngăn chặn lỗ hổng:
    Có một quá trình “xây dựng và triển khai” tốt (tốt nhất là tự động). Cần một quá trình audit các chính xác bảo mật trên máy chủ trước khi triển khai.

    6. Sensitive data exposure (Rò rỉ dữ liệu nhạy cảm)

    Lỗ hổng này thuộc về khía cạnh crypto và tài nguyên. Dữ liệu nhạy cảm phải được mã hóa mọi lúc, bao gồm cả khi gửi đi và khi lưu trữ – không được phép có ngoại lệ. Thông tin thẻ tín dụng và mật khẩu người dùng không bao giờ được gửi đi hoặc được lưu trữ không được mã hóa. Rõ ràng thuật toán mã hóa và hashing không phải là một cách bảo mật yếu. Ngoài ra, các tiêu chuẩn an ninh web đề nghị sử dụng AES (256 bit trở lên) và RSA (2048 bit trở lên).

    Cần phải nói rằng các Session ID và dữ liệu nhạy cảm không nên được truyền trong các URL và cookie nhạy cảm nên có cờ an toàn.

    Cách ngăn chặn lỗ hổng:

    • Sử dụng HTTPS có chứng chỉ phù hợp và PFS (Perfect Forward Secrecy). Không nhận bất cứ thông tin gì trên các kết nối không phải là HTTPS. Có cờ an toàn trên cookie.
    • Bạn cần hạn chế các dữ liệu nhạy cảm có khả năng bị lộ của mình. Nếu bạn không cần những dữ liệu nhạy cảm này, hãy hủy nó. Dữ liệu bạn không có không thể bị đánh cắp.
    • Không bao giờ lưu trữ thông tin thẻ tín dụng, nếu không muốn phải đối phó với việc tuân thủ PCI. Hãy đăng ký một bộ xử lý thanh toán như Stripe hoặc Braintree.
    • Nếu bạn có dữ liệu nhạy cảm mà bạn thực sự cần, lưu trữ mã hóa nó và đảm bảo rằng tất cả các mật khẩu được sử dụng hàm Hash để bảo vệ. Đối với Hash, nên sử dụng bcrypt. Nếu bạn không sử dụng mã hoá bcrypt, hãy tìm hiểu về mã Salt để ngăn ngừa rainbow table attack.

    Không lưu trữ các khóa mã hóa bên cạnh dữ liệu được bảo vệ. Việc này giống như khóa xe mà cắm chìa luôn ở đó. Bảo vệ bản sao lưu của bạn bằng mã hóa và đảm bảo các khóa của bạn là riêng tư.

    7. Missing function level access control (lỗi phân quyền)

    Đây chỉ là sai sót trong vấn đề phân quyền. Nó có nghĩa là khi một hàm được gọi trên máy chủ, quá trình phân quyền không chính xác. Các nhà phát triển dựa vào thực tế là phía máy chủ tạo ra giao diện người dùng và họ nghĩ rằng khách hàng không thể truy cập các chức năng nếu không được cung cấp bởi máy chủ.

    Tuy nhiên, kẻ tấn công luôn có thể yêu cầu các chức năng “ẩn” và sẽ không bị cản trở bởi việc giao diện người dùng không cho phép thực hiện các chức năng này. Hãy tưởng tượng trong giao diện người dùng chỉ có bảng điều khiển/admin và nút nếu người dùng thực sự là quản trị viên. Không có gì ngăn cản kẻ tấn công phát hiện ra những tính năng này và lạm dụng nó nếu không phân quyền.

    Cách ngăn chặn lỗ hổng: Ở phía máy chủ, phải luôn được phân quyền một cách triệt để từ khâu thiết kế. Không có ngoại lệ – mọi lỗ hổng sẽ dẫn đến đủ các vấn đề nghiêm trọng.

    8. Cross Site Request Forgery (CSRF)

    Đây là một ví dụ của cuộc tấn công deputy attack. Trình duyệt bị đánh lừa bởi một số bên thứ ba lạm dụng quyền hạn. 
    Ví dụ: trang web của bên thứ ba gửi yêu cầu đến trang web đích (ví dụ: ngân hàng của bạn) sử dụng trình duyệt của bạn với các dữ liệu như cookie và phiên người dùng. Nếu bạn đang đăng nhập vào một trang trên trang chủ của ngân hàng và trang đó dễ bị tấn công, một tab khác có thể cho phép kẻ tấn công đóng giả người quản trị. Deputy là khi trang web lạm dụng quyền hạn của mình (session cookies) để làm điều gì đó mà kẻ tấn công yêu cầu.

    Chúng ta có thể xem xét ví dụ sau:

    • Kẻ tấn công là Alice chọn mục tiêu là chiếc ví của Todd bằng cách chuyển một phần tiền của Todd cho cô ta. Ngân hàng của Todd đã gặp phải lỗ hổng CSRF. Để gửi tiền, Todd phải truy cập vào URL sau:
    • Sau khi URL này được mở ra, một trang thành công được trình bày cho Todd và việc chuyển đổi đã hoàn tất. Alice cũng biết rằng Todd thường ghé thăm một trang web dưới quyền kiểm soát của cô tại blog.aliceisawesome.com, nơi cô đặt đoạn mã sau đây:
    <img src = "http://example.com/app/transferFunds?amount=1500&destinationAccount=4673243243" width = "0" height = "0" />
    • Khi truy cập trang web của Alice, trình duyệt của Todd nghĩ rằng Alice liên kết đến một hình ảnh và tự động đưa ra yêu cầu HTTP GET để lấy “hình ảnh”, nhưng điều này thực sự hướng dẫn ngân hàng của Todd chuyển $1500 đến Alice.

    Cách ngăn chặn lỗ hổng:

    Lưu trữ một Token bí mật trong một trường form ẩn mà không thể truy cập được từ trang web của bên thứ ba. Tất nhiên bạn phải xác minh trường ẩn này. Một số trang web yêu cầu mật khẩu của bạn cũng như khi sửa đổi các cài đặt nhạy cảm.

    9. Using component with known vulnerabilities

    Đây là vấn đề xảy ra khi sử dụng các bộ thư viện đã tồn tại lỗ hổng. Trước khi tích hợp một mã nguồn mới vào website, hãy thực hiện một số nghiên cứu hoặc kiểm tra bảo mật. Sử dụng mã nguồn mà bạn nhận được từ một người ngẫu nhiên trên GitHub hoặc một số diễn đàn có thể rất thuận tiện. Nhưng hãy sẵn sàng trước nguy cơ đối diện với một lỗ hổng bảo mật web nghiêm trọng.

    Ví dụ: Nhiều trường hợp, trang admin bị lộ không phải vì các lập trình viên sai sót, mà vì phần mềm của bên thứ ba vẫn chưa được cập nhật. Nếu bạn nghĩ rằng họ sẽ không tìm thấy cài đặt phpmyadmin ẩn của bạn, hãy tìm hiểu về dirbuster.

    Cách ngăn chặn lỗ hổng:

    Chú ý cẩn thận khi sử dụng các thành phần của bên thứ 3, không nên là một coder copy-paste. Kiểm tra cẩn thận các đoạn code quan trọng của bạn. Nếu các đoạn code này có lỗ hổng, tin tặc có thể đọc cơ sở dữ liệu, tệp tin cấu hình, mật khẩu… của bạn.

    • Cập nhật mọi thứ: Đảm bảo bạn đang sử dụng phiên bản mới nhất của tất cả mọi thứ và có kế hoạch cập nhật chúng thường xuyên. Ít nhất là đăng ký bản tin về các lỗ hổng bảo mật mới liên quan đến sản phẩm.

    10. Unvalidated redirects and forwards

    Đây lại là vấn đề về lọc đầu vào. Giả sử rằng trang đích có một mô-đun redirect.php lấy URL làm tham số. Thao tác với tham số này có thể tạo ra một URL trên targetite.com chuyển hướng trình duyệt đến địa chỉ malwareinstall.com. Khi người dùng nhìn thấy liên kết, họ sẽ thấy liên kết targetite.com/blahblahblah tin cậy và truy cập vào. Họ ít biết rằng địa chỉ này thực ra chuyển tới trang nhúng phần mềm độc hại (hoặc bất kỳ trang độc hại khác). Ngoài ra, kẻ tấn công có thể chuyển hướng trình duyệt sang targetite.com/deleteprofile?confirm=1.

    Cách ngăn chặn lỗ hổng:

    • Không sử dụng chức năng chuyển hướng.
    • Có một danh sách tĩnh các vị trí hợp lệ để chuyển hướng đến.
    • Có Whitelist tham số người dùng xác định.

    Tổng hợp các cộng cụ quét lỗ hổng website tốt nhất