Làm thế nào để tránh những lỗi lập trình căn bản nhất và nâng cao khả năng bảo mật cho hệ thống website của bạn.
PHP là ngôn ngữ lập trình dễ học nên có thể nói là ngôn ngữ lập trình web được học và sử dụng nhiều nhất hiện nay. Nó không cần bạn phải biết thêm bất kì một ngôn ngữ lập trình nào trước khi tìm hiểu về PHP. Điều này có lẽ là điểm thuận lợi cho những người mới bắt đầu bước vào con đường lập trình viên. Nhưng cũng thật không may, chính nó làm cho nhiều lập trình viên không có điều kiện tiếp xúc với những lỗi bảo mật tiềm ẩn dễ mắc phải. Dưới đây xin liệt kê những lỗi lập trình phổ biến mà bạn có thể mắc phải trong quá trình làm việc với PHP.
Phụ mục
Quy luật 1: Đừng bao giờ tin vào người dùng
Mình có dịp nhắc đến quy luật này của Dave Child trong bài viết Mười nguyên tắc bảo mật cơ bản của những bậc thầy PHP đã nói ở trên. Nếu bạn là một lập trình viên, bạn không bao giờ được tin rằng người dùng sẽ gửi cho bạn một gói dữ liệu đúng tiêu chuẩn mà bạn đã đề ra trước khi đưa vào cơ sở dữ liệu. Rất nhiều trường hợp website bị lộ những thông tin nhạy cảm và các lỗi bảo mật khi người dùng nhập những dữ liệu không tương thích với thông tin mà bạn yêu cầu.
Do đó, trước khi bạn quyết định thực hiện một thao tác nào đó với dữ liệu do người dùng nhập vào, bạn đừng bao giờ bỏ qua tính hợp lệ của nó bằng các thao tác kiểm tra. Đừng bao giờ tin vào người dùng là nguyên tắc hàng đầu của tôi. Trên bàn làm việc của tôi, tôi có một mảnh giấy gọi là “PHP Security” và nguyên tắc này luôn được tôi in đậm và ở vị trí đầu tiên.
Các biến toàn cục(Global Variables)
Biến là một phần của ngôn ngữ lập trình. Trong PHP, bạn có thể sử dụng register_globals trong file php.ini để khởi tạo các biến toàn cục – những biến mà bạn không cần phải tạo ra nó một cách rõ ràng.
Hãy cùng xem xét đoạn mã dưới đây:
if ($password == "my_password") { $authorized = 1; } if ($authorized == 1) { echo "Lots of important stuff."; } |
Đoạn mã trên nhìn có vẻ ổn và trên thực tế là nó sẽ hoạt động tốt, không phát sinh lỗi bảo mật gì trong trường hợp bình thường. Tuy nhiên, nếu máy chủ được cấp quyền register_globals = on và một chuỗi ?authorized=1 được đặt trên URL thì nó lại là chuyện khác :D Trong trường hợp này, biến $authorized lúc này sẽ có giá trị 1 và cho phép bất kì ai sử dụng đoạn URL này vượt và hàng rào mật khẩu và truy cập vào khu vực cần sử dụng mật khẩu.
Lỗi này khá phổ biến trong các ứng dụng lập trình bằng PHP.
May mắn thay, việc khắc phục lỗi này khá đơn giản. Đầu tiên, việc bạn có thể làm là tắt register_globals đi và khởi tạo một cách chính xác giá trị cho biến $authorized bằng cách thêm $authorized = 0 vào đầu đoạn mã như sau:
$authorized = 0; if ($password == "my_password") { $authorized = 1; } if ($authorized == 1) { echo "Lots of important stuff."; } |
Error Messages
Error Messages có thể nói là công cụ khá hữu ích cả cho người lập trình viên lẫn cho hacker. Đối với lập trình viên, Error Messages giúp phát hiện các lỗi và sửa lỗi dễ dàng. Còn đối với hacker, nó là phần nội dung có thể dùng khai thác các thông tin liên quan đến hệ thống, các thông tin từ cây thư mục, thông tin kết nối database, thông tin user đến thông tin password…
Cách tốt nhất để bảo mật là bạn nên tắt Error Messages khi cho website chạy trực tuyến bằng cách thiết lập error_reporting về 0 trong file php.ini hoặc bằng .htaccess. Nếu bạn đang thực hiện việc xây dựng website bạn có thể thay đổi giá trị này để việc kiểm tra các lỗi dễ dàng hơn.
SQL Injection
Một trong những thế mạnh của PHP là khả năng liên lạc dễ dàng với cơ sở dữ liệu, nhất là MySQL. Tuy nhiên, điều này cũng tiềm ẩn nhiều nguy cơ bảo mật mà hay gặp nhất là SQL Injection – người dùng sử dụng một lỗi bảo mật nào đó để truy vấn trực tiếp vào cơ sở dữ liệu của bạn và lấy các thông tin cần thiết.
Chúng ta hãy bắt đầu việc phân tích lỗi này bằng một truy vấn kiểm tra đăng nhập (đây là phần được rất nhiều website thực hiện):
$check = mysql_query("SELECT Username, Password, UserLevel FROM Users WHERE Username = '".$_POST['username']."' and Password = '".$_POST['password']."'"); |
Nhìn có vẻ ổn ? Và thực tế nó sẽ làm việc tốt khi cần kiểm tra thông tin người đăng nhập có hợp lệ hay không. Nhưng một hôm nào đó, tôi nhập vào trường username thông tin sau
' OR 1=1 #
Lúc này câu truy vẫn sẽ được thay đổi thành:
SELECT Username, Password FROM Users WHERE Username = '' OR 1=1 #' and Password = '' |
Ký tự thăng (#) cho lệnh truy vấn sẽ xác định đoạn phía sau nó là một đoạn ghi chú (comment) và sẽ bỏ qua. Lúc này, câu truy vấn sẽ thực hiện đến đoạn trước dấu thăng (#) mà thôi. 1 thì luôn luôn bằng 1 đúng không :D . Và như vậy, hacker dễ dàng vượt qua vòng kiểm tra mật khẩu :( . Chỉ cần biết thêm username của một quản trị viên nào đó nữa là có thể đăng nhập dễ dàng.
Bằng một chút sáng tạo của mình, hacker có thể khai thác tiếp rất nhiều thông tin của người quản trị này như thông tin thẻ tín dụng, địa chỉ email hay có thể chiếm quyền quản trị website để khai thác thông tin người dùng.
May quá, lỗi này có thể được vô hiệu hóa dễ dàng bằng cách kiểm tra các dấu nháy (‘) do người dùng nhập và vô hiệu hóa chúng bằng hàm sau (hoặc bạn có thể viết thêm để kiểm tra kĩ càng hơn):
function make_safe($variable) { $variable = mysql_real_escape_string(trim($variable)); return $variable; } |
Bây giờ, trước khi chạy đoạn lệnh truy vấn cơ sở dữ liệu đã nói ở trên, chúng ta sẻ dụng hàm make_safe để vô hiệu hóa các kí tự nhạy :
$username = make_safe($_POST['username']); $password = make_safe($_POST['password']); $check = mysql_query("SELECT Username, Password, UserLevel FROM Users WHERE Username = '".$username."' and Password = '".$password."'"); |
Bây giờ, các dữ liệu độc hại ở trên được vô hiệu hóa trước khi thực hiện lệnh truy vấn. Lúc này dữ liệu nhập vào được sửa thành “\ ‘OR 1 = 1 #” trước khi thực hiện truy vấn.
SELECT Username, Password, UserLevel FROM Users WHERE Username = '' OR 1=1 #' and Password = '' |
Bây giờ, trừ khi trong cơ sở dữ liệu của bạn chứa 1 dòng dữ liệu đặc biệt nào đó mà hacker có thể không cần đăng nhập. Nếu không, chúng ta không cần phải lo.
Khai thác tập tin
Một số trang web chạy đoạn URL như thế này:
index.php?page=contactus.html |
Với trường hợp này, thông thường mục đích của lập trình viên là chạy đoạn mã được lưu trong file contactus.html trong file index.php. Chuyện gì sẽ xảy ra nếu người dùng thay thế contactus.html thành một trang nào đó ? Ví dụ, nếu bạn đang sử dụng Apache ‘s mod_auth để bảo vệ các tập tin và có lưu mật khẩu của bạn trong một tập tin có tên “. htpasswd” (tên gọi thông thường), sau đó nếu người dùng đã truy cập vào địa chỉ sau, script sẽ ra tên người dùng của bạn và mật khẩu:
index.php?page=.htpasswd |
Tệ hại hơn, họ có thể chạy tập tin trên hosting của họ trên website của bạn để khai thác thông tin.
Bạn nên lo lắng ? Nên !
Trước tiên, hãy chắn chắn bạn thiết lập đúng giá trị open_basedir trong tập tin php.ini và thiết lập allow_url_fopen=off. Điều đó sẽ ngăn chặn hầu hết các loại tấn công bằng cách ngăn chặn việc xử lý tập tin từ xa và tập tin hệ thống. Tiếp theo, nếu bạn, có thể kiểm tra các tập tin yêu cầu đối với một danh sách các tập tin hợp lệ. Nếu bạn giới hạn các tập tin mà có thể được truy cập bằng cách sử dụng mã này, bạn sẽ tiết kiệm cho mình rất nhiều tình tiết tăng nặng sau đó.
Sử dụng các giá trị mặc định
MySQL sử dụng tài khoản mặc định là root và mật khẩu rỗng, SQL Server sử dụng tài khoản ‘sa’ để đăng nhập với mật khẩu rỗng. Nếu hacker tìm được địa chỉ máy chủ của bạn thì đây chính là những thông tin đăng nhập đầu tiên mà họ cố gắng khai thác. Do đó, bạn nên xóa hoặc thay đổi nó đi.
Để tập tin cài đặt (install)
Nhiều mã nguồn PHP đi kèm với những tập tin cài đặt (nhất là với các mã nguồn mở). Nhiều trường hợp sau khi cài đặt bạn lại quên xóa nó đi. Thông thường, các mã nguồn sẽ gửi cảnh báo cho bạn nếu bạn chưa xóa tập tin cài đặt nhưng cũng có những mã nguồn không làm việc đó. Nếu bạn không xóa tập tin này đi, một ngày đẹp trời nào đó hacker có thể lợi dụng việc này để cài đặt lại hệ thống và chép đè toàn bộ cơ sở dữ liệu của bạn. Lúc đó bạn sẽ ôm hận dài dài prr
Ngăn ngừa khả năng dự đoán
Website của bạn có chút “số má” sẽ kéo theo những người tò mò muốn phá hoại. Điểm đầu tiên họ muốn tìm đến là thư mục quản trị hệ thống của bạn. Thông thường, họ sẽ tìm đến với các thư mục có thên ‘admin’ hoặc ‘administrator’, ‘admincp’…
Đặt tên thực mục quản trị như vậy nghĩa là bạn đang đặt website của mình trước con mắt tò mò và nâng cao mức độ nguy hiểm cả website. Hãy tưởng tượng với tên
http://www.yoursite.com/jsfh8sfsifuhsi8392 |
thì hacker sẽ mò ra tên thư mục quản trị của bạn dễ dàng hay không ?
Trong trường hợp việc tìm kiếm thư mục gặp khó khăn, bạn sẽ ngăn chặn được phần nào khả năng bị tấn công của mình.
Trường hợp tương tự cho user và password đơn giản cũng có thể giúp hacker dễ dàng dự đoán ra.
Cuối cùng, hãy chắn chắn những thông điệp bạn đưa ra khi có lỗi xảy ra được kiểm soát chặt chẽ. Đừng đưa các thông điệp như ‘Tên người dùng không tồn tại’ hoặc ‘mật khẩu không chính xác với tên đăng nhập này’. Một hacker tinh ý sẽ dễ dàng dự đoán được user và mật khẩu đăng nhập hợp lệ dựa vào những thông báo loại này.
Cuối cùng, không có gì là hoàn hảo
Nếu bạn cho rằng khả năng lập trình của bạn là hoàn hảo và website của bạn không thể bị tấn công thì đó là sai lầm lớn nhất. Lập trình viên là người sống chung với lỗi, do đó bạn phải luôn cẩn thận và chuẩn bị cho những tình huống xấu nhất có thể