Thoát xml python

Bài viết này tập trung vào cách người ta có thể phân tích cú pháp một tệp XML định dạng nhất và trích xuất một số dữ liệu hữu ích từ nó theo cách có cấu trúc.

XML. XML là viết tắt của eXtensible Markup Language. Nó được thiết kế để lưu trữ và chuyển dữ liệu. Nó được thiết kế để người và máy đều có thể đọc được. Đó là lý do tại sao, các mục tiêu thiết kế của XML nhấn mạnh vào tính đơn giản, tính tổng và khả năng sử dụng trên Internet
Tệp XML được phân tích cú pháp theo hướng dẫn này thực sự là một nguồn cấp dữ liệu RSS

RSS. RSS (Rich Site Summary, thường được gọi là Really Simple Syndication) sử dụng một nhóm các định dạng nguồn cấp dữ liệu web tiêu chuẩn để xuất bản các mục blog, tiêu đề tin tức, âm thanh, video được cập nhật thường xuyên. RSS is raw raw text is XML format

  • Định dạng bản thân RSS tương đối dễ đọc bởi các quy trình tự động và cả con người
  • RSS được xử lý theo hướng dẫn này là nguồn RSS của các bài báo hàng đầu từ một trang web phổ biến. Bạn có thể kiểm tra nó ở đây. Mục tiêu của chúng tôi là xử lý các nguồn cấp RSS này (hoặc tệp XML) và lưu nó ở một số định dạng khác để sử dụng trong tương lai

Mô-đun Python được sử dụng. Bài viết này sẽ tập trung vào việc sử dụng mô-đun xml có sẵn trong python để phân tích cú pháp XML và trọng tâm chính sẽ là API ElementTree XML của mô-đun này

Bài viết này tập trung vào việc cung cấp hướng dẫn rõ ràng, đơn giản, khả thi để ngăn chặn các lỗi SQL Injection trong ứng dụng của bạn. Thật không may, các cuộc tấn công SQL Injection rất phổ biến và điều này là do hai yếu tố

  1. sự phổ biến đáng kể của các lỗ hổng SQL Injection và
  2. sức hấp dẫn của mục tiêu (i. e. , cơ sở dữ liệu thường chứa tất cả dữ liệu thú vị/quan trọng cho ứng dụng của bạn)

Các lỗ hổng SQL Injection được đưa ra khi các nhà phát triển phần mềm tạo các truy vấn cơ sở dữ liệu động được xây dựng bằng cách nối chuỗi bao gồm đầu vào do người dùng cung cấp. Để tránh lỗi SQL injection rất đơn giản. Các nhà phát triển cần phải hoặc. a) ngừng viết các truy vấn động có nối chuỗi;

Bài viết này cung cấp một tập hợp các kỹ thuật đơn giản để ngăn chặn các lỗ hổng SQL Injection bằng cách tránh hai vấn đề này. Những kỹ thuật này có thể được sử dụng thực tế với bất kỳ loại ngôn ngữ lập trình nào với bất kỳ loại cơ sở dữ liệu nào. Có các loại cơ sở dữ liệu khác, chẳng hạn như cơ sở dữ liệu XML, có thể gặp vấn đề tương tự (e. g. , XPath và XQuery injection) và những kỹ thuật này cũng có thể được sử dụng để bảo vệ chúng

phòng thủ chính

  • lựa chọn 1. Sử dụng các câu lệnh đã chuẩn bị (với các truy vấn được tham số hóa)
  • Lựa chọn 2. Sử dụng các thủ tục lưu trữ được xây dựng đúng cách
  • Tùy chọn 3. Xác thực đầu vào danh sách cho phép
  • Tùy chọn 4. Thoát khỏi tất cả đầu vào do người dùng cung cấp

phòng thủ bổ sung

  • Cũng. Thực thi đặc quyền tối thiểu
  • Cũng. Thực hiện Xác thực đầu vào trong danh sách cho phép dưới dạng Bảo vệ phụ

Ví dụ không an toàn

Lỗi SQL injection thường trông như thế này

Ví dụ (Java) sau đây KHÔNG AN TOÀN và sẽ cho phép kẻ tấn công đưa mã vào truy vấn sẽ được thực thi bởi cơ sở dữ liệu. Tham số "tên khách hàng" chưa được xác thực chỉ được thêm vào truy vấn cho phép kẻ tấn công đưa bất kỳ mã SQL nào chúng muốn. Thật không may, phương pháp này để truy cập cơ sở dữ liệu là quá phổ biến

String query = "SELECT account_balance FROM user_data WHERE user_name = "
             + request.getParameter("customerName");
try {
    Statement statement = connection.createStatement( ... );
    ResultSet results = statement.executeQuery( query );
}
...

phòng thủ chính

Lựa chọn phòng thủ 1. Báo cáo đã chuẩn bị (với Truy vấn được tham số hóa)

Việc sử dụng các câu lệnh đã chuẩn bị với liên kết biến (còn gọi là truy vấn được tham số hóa) là cách mà tất cả các nhà phát triển nên được dạy cách viết truy vấn cơ sở dữ liệu trước tiên. Chúng đơn giản để viết và dễ hiểu hơn các truy vấn động. Các truy vấn được tham số hóa buộc nhà phát triển trước tiên xác định tất cả mã SQL, sau đó chuyển từng tham số vào truy vấn sau. Kiểu mã hóa này cho phép cơ sở dữ liệu phân biệt giữa mã và dữ liệu, bất kể đầu vào của người dùng được cung cấp là gì

Các câu lệnh đã chuẩn bị đảm bảo rằng kẻ tấn công không thể thay đổi mục đích của truy vấn, ngay cả khi các lệnh SQL được chèn bởi kẻ tấn công. Trong ví dụ an toàn bên dưới, nếu kẻ tấn công nhập ID người dùng của

// This should REALLY be validated too
String custname = request.getParameter("customerName");
// Perform input validation to detect attacks
String query = "SELECT account_balance FROM user_data WHERE user_name = ? ";
PreparedStatement pstmt = connection.prepareStatement( query );
pstmt.setString( 1, custname);
ResultSet results = pstmt.executeQuery( );
8, truy vấn được tham số hóa sẽ không dễ bị tấn công và thay vào đó sẽ tìm kiếm tên người dùng khớp với toàn bộ chuỗi
// This should REALLY be validated too
String custname = request.getParameter("customerName");
// Perform input validation to detect attacks
String query = "SELECT account_balance FROM user_data WHERE user_name = ? ";
PreparedStatement pstmt = connection.prepareStatement( query );
pstmt.setString( 1, custname);
ResultSet results = pstmt.executeQuery( );
8

Đề xuất ngôn ngữ cụ thể

  • Java EE – sử dụng
    String query = "SELECT account_balance FROM user_data WHERE user_name = ?";
    try {
      OleDbCommand command = new OleDbCommand(query, connection);
      command.Parameters.Add(new OleDbParameter("customerName", CustomerName Name.Text));
      OleDbDataReader reader = command.ExecuteReader();
      // …
    } catch (OleDbException se) {
      // error handling
    }
    
    0 với các biến liên kết
  • NET – sử dụng các truy vấn được tham số hóa như
    String query = "SELECT account_balance FROM user_data WHERE user_name = ?";
    try {
      OleDbCommand command = new OleDbCommand(query, connection);
      command.Parameters.Add(new OleDbParameter("customerName", CustomerName Name.Text));
      OleDbDataReader reader = command.ExecuteReader();
      // …
    } catch (OleDbException se) {
      // error handling
    }
    
    1 hoặc
    String query = "SELECT account_balance FROM user_data WHERE user_name = ?";
    try {
      OleDbCommand command = new OleDbCommand(query, connection);
      command.Parameters.Add(new OleDbParameter("customerName", CustomerName Name.Text));
      OleDbDataReader reader = command.ExecuteReader();
      // …
    } catch (OleDbException se) {
      // error handling
    }
    
    2 với các biến liên kết
  • PHP – sử dụng PDO với các truy vấn được nhập tham số mạnh (sử dụng bindParam())
  • Ngủ đông - sử dụng
    String query = "SELECT account_balance FROM user_data WHERE user_name = ?";
    try {
      OleDbCommand command = new OleDbCommand(query, connection);
      command.Parameters.Add(new OleDbParameter("customerName", CustomerName Name.Text));
      OleDbDataReader reader = command.ExecuteReader();
      // …
    } catch (OleDbException se) {
      // error handling
    }
    
    3 với các biến liên kết (được gọi là tham số được đặt tên trong Hibernate)
  • SQLite - sử dụng
    String query = "SELECT account_balance FROM user_data WHERE user_name = ?";
    try {
      OleDbCommand command = new OleDbCommand(query, connection);
      command.Parameters.Add(new OleDbParameter("customerName", CustomerName Name.Text));
      OleDbDataReader reader = command.ExecuteReader();
      // …
    } catch (OleDbException se) {
      // error handling
    }
    
    4 để tạo đối tượng câu lệnh

Trong một số ít trường hợp, các câu lệnh được chuẩn bị sẵn có thể gây hại cho hiệu suất. Khi đối mặt với tình huống này, tốt nhất là a) xác thực mạnh mẽ tất cả dữ liệu hoặc b) thoát khỏi tất cả đầu vào do người dùng cung cấp bằng cách sử dụng quy trình thoát dành riêng cho nhà cung cấp cơ sở dữ liệu của bạn như được mô tả bên dưới, thay vì sử dụng câu lệnh đã chuẩn bị sẵn

Ví dụ về câu lệnh chuẩn bị Java an toàn

Ví dụ mã sau đây sử dụng

String query = "SELECT account_balance FROM user_data WHERE user_name = ?";
try {
  OleDbCommand command = new OleDbCommand(query, connection);
  command.Parameters.Add(new OleDbParameter("customerName", CustomerName Name.Text));
  OleDbDataReader reader = command.ExecuteReader();
  // …
} catch (OleDbException se) {
  // error handling
}
5, triển khai truy vấn được tham số hóa của Java, để thực hiện cùng một truy vấn cơ sở dữ liệu

// This should REALLY be validated too
String custname = request.getParameter("customerName");
// Perform input validation to detect attacks
String query = "SELECT account_balance FROM user_data WHERE user_name = ? ";
PreparedStatement pstmt = connection.prepareStatement( query );
pstmt.setString( 1, custname);
ResultSet results = pstmt.executeQuery( );

C# an toàn. Ví dụ về câu lệnh chuẩn bị NET

Với. NET, nó thậm chí còn đơn giản hơn. Việc tạo và thực hiện truy vấn không thay đổi. Tất cả những gì bạn phải làm chỉ đơn giản là chuyển các tham số cho truy vấn bằng cách sử dụng lệnh gọi

String query = "SELECT account_balance FROM user_data WHERE user_name = ?";
try {
  OleDbCommand command = new OleDbCommand(query, connection);
  command.Parameters.Add(new OleDbParameter("customerName", CustomerName Name.Text));
  OleDbDataReader reader = command.ExecuteReader();
  // …
} catch (OleDbException se) {
  // error handling
}
6 như được hiển thị ở đây

String query = "SELECT account_balance FROM user_data WHERE user_name = ?";
try {
  OleDbCommand command = new OleDbCommand(query, connection);
  command.Parameters.Add(new OleDbParameter("customerName", CustomerName Name.Text));
  OleDbDataReader reader = command.ExecuteReader();
  // …
} catch (OleDbException se) {
  // error handling
}

Chúng tôi đã chỉ ra các ví dụ trong Java và. NET nhưng thực tế là tất cả các ngôn ngữ khác, bao gồm Cold Fusion và Classic ASP, đều hỗ trợ các giao diện truy vấn được tham số hóa. Ngay cả các lớp trừu tượng hóa SQL, như Ngôn ngữ truy vấn ngủ đông (HQL) cũng có cùng loại sự cố tiêm nhiễm (mà chúng tôi gọi là HQL Injection). HQL cũng hỗ trợ các truy vấn được tham số hóa, vì vậy chúng tôi có thể tránh được sự cố này

Ví dụ về câu lệnh đã chuẩn bị cho Ngôn ngữ truy vấn ngủ đông (HQL) (Tham số được đặt tên)

//First is an unsafe HQL Statement
Query unsafeHQLQuery = session.createQuery("from Inventory where productID='"+userSuppliedParameter+"'");
//Here is a safe version of the same query using named parameters
Query safeHQLQuery = session.createQuery("from Inventory where productID=:productid");
safeHQLQuery.setParameter("productid", userSuppliedParameter);

Để biết ví dụ về các truy vấn được tham số hóa bằng các ngôn ngữ khác, bao gồm Ruby, PHP, Cold Fusion và Perl, hãy xem Bảng gian lận tham số hóa truy vấn hoặc trang web này

Các nhà phát triển có xu hướng thích cách tiếp cận Tuyên bố đã Chuẩn bị vì tất cả mã SQL nằm trong ứng dụng. Điều này làm cho ứng dụng của bạn tương đối độc lập với cơ sở dữ liệu

Lựa chọn phòng thủ 2. thủ tục lưu trữ

Các thủ tục được lưu trữ không phải lúc nào cũng an toàn trước SQL injection. Tuy nhiên, một số cấu trúc lập trình thủ tục được lưu trữ tiêu chuẩn nhất định có tác dụng tương tự như việc sử dụng các truy vấn được tham số hóa khi được triển khai một cách an toàn, đây là tiêu chuẩn cho hầu hết các ngôn ngữ thủ tục được lưu trữ

Chúng yêu cầu nhà phát triển chỉ xây dựng các câu lệnh SQL với các tham số được tham số hóa tự động trừ khi nhà phát triển thực hiện điều gì đó phần lớn nằm ngoài quy chuẩn. Sự khác biệt giữa các câu lệnh đã chuẩn bị và các thủ tục được lưu trữ là mã SQL cho một thủ tục được lưu trữ được xác định và lưu trữ trong chính cơ sở dữ liệu, sau đó được gọi từ ứng dụng. Cả hai kỹ thuật này đều có hiệu quả như nhau trong việc ngăn chặn SQL injection, vì vậy tổ chức của bạn nên chọn cách tiếp cận nào phù hợp nhất với mình

Ghi chú. "Được triển khai an toàn" có nghĩa là quy trình được lưu trữ không bao gồm bất kỳ việc tạo SQL động không an toàn nào. Các nhà phát triển thường không tạo SQL động bên trong các thủ tục được lưu trữ. Tuy nhiên, có thể làm được, nhưng nên tránh. Nếu không thể tránh được, quy trình được lưu trữ phải sử dụng xác thực đầu vào hoặc thoát thích hợp như được mô tả trong bài viết này để đảm bảo rằng tất cả đầu vào do người dùng cung cấp cho quy trình được lưu trữ không thể được sử dụng để đưa mã SQL vào truy vấn được tạo động. Kiểm toán viên phải luôn tìm cách sử dụng

String query = "SELECT account_balance FROM user_data WHERE user_name = ?";
try {
  OleDbCommand command = new OleDbCommand(query, connection);
  command.Parameters.Add(new OleDbParameter("customerName", CustomerName Name.Text));
  OleDbDataReader reader = command.ExecuteReader();
  // …
} catch (OleDbException se) {
  // error handling
}
7,
String query = "SELECT account_balance FROM user_data WHERE user_name = ?";
try {
  OleDbCommand command = new OleDbCommand(query, connection);
  command.Parameters.Add(new OleDbParameter("customerName", CustomerName Name.Text));
  OleDbDataReader reader = command.ExecuteReader();
  // …
} catch (OleDbException se) {
  // error handling
}
8 hoặc
String query = "SELECT account_balance FROM user_data WHERE user_name = ?";
try {
  OleDbCommand command = new OleDbCommand(query, connection);
  command.Parameters.Add(new OleDbParameter("customerName", CustomerName Name.Text));
  OleDbDataReader reader = command.ExecuteReader();
  // …
} catch (OleDbException se) {
  // error handling
}
9 trong các thủ tục được lưu trữ của SQL Server. Hướng dẫn kiểm tra tương tự là cần thiết cho các chức năng tương tự cho các nhà cung cấp khác

Ngoài ra còn có một số trường hợp thủ tục được lưu trữ có thể làm tăng rủi ro. Ví dụ: trên máy chủ MS SQL, bạn có 3 vai trò mặc định chính.

//First is an unsafe HQL Statement
Query unsafeHQLQuery = session.createQuery("from Inventory where productID='"+userSuppliedParameter+"'");
//Here is a safe version of the same query using named parameters
Query safeHQLQuery = session.createQuery("from Inventory where productID=:productid");
safeHQLQuery.setParameter("productid", userSuppliedParameter);
0,
//First is an unsafe HQL Statement
Query unsafeHQLQuery = session.createQuery("from Inventory where productID='"+userSuppliedParameter+"'");
//Here is a safe version of the same query using named parameters
Query safeHQLQuery = session.createQuery("from Inventory where productID=:productid");
safeHQLQuery.setParameter("productid", userSuppliedParameter);
1 và
//First is an unsafe HQL Statement
Query unsafeHQLQuery = session.createQuery("from Inventory where productID='"+userSuppliedParameter+"'");
//Here is a safe version of the same query using named parameters
Query safeHQLQuery = session.createQuery("from Inventory where productID=:productid");
safeHQLQuery.setParameter("productid", userSuppliedParameter);
2. Trước khi các thủ tục được lưu trữ được sử dụng, DBA sẽ cấp quyền db_datareader hoặc db_datawriter cho người dùng dịch vụ web, tùy thuộc vào yêu cầu. Tuy nhiên, các thủ tục được lưu trữ yêu cầu quyền thực thi, một vai trò không có sẵn theo mặc định. Một số thiết lập trong đó quyền quản lý người dùng được tập trung, nhưng bị giới hạn ở 3 vai trò đó, khiến tất cả các ứng dụng web chạy dưới quyền db_owner để các thủ tục được lưu trữ có thể hoạt động. Đương nhiên, điều đó có nghĩa là nếu một máy chủ bị vi phạm, kẻ tấn công có toàn quyền đối với cơ sở dữ liệu, nơi trước đây chúng chỉ có thể có quyền truy cập đọc.

Ví dụ về thủ tục lưu trữ Java an toàn

Ví dụ mã sau đây sử dụng

//First is an unsafe HQL Statement
Query unsafeHQLQuery = session.createQuery("from Inventory where productID='"+userSuppliedParameter+"'");
//Here is a safe version of the same query using named parameters
Query safeHQLQuery = session.createQuery("from Inventory where productID=:productid");
safeHQLQuery.setParameter("productid", userSuppliedParameter);
3, triển khai giao diện thủ tục được lưu trữ của Java, để thực hiện cùng một truy vấn cơ sở dữ liệu. Thủ tục được lưu trữ
//First is an unsafe HQL Statement
Query unsafeHQLQuery = session.createQuery("from Inventory where productID='"+userSuppliedParameter+"'");
//Here is a safe version of the same query using named parameters
Query safeHQLQuery = session.createQuery("from Inventory where productID=:productid");
safeHQLQuery.setParameter("productid", userSuppliedParameter);
4 sẽ phải được xác định trước trong cơ sở dữ liệu và triển khai chức năng tương tự như truy vấn được xác định ở trên

// This should REALLY be validated
String custname = request.getParameter("customerName");
try {
  CallableStatement cs = connection.prepareCall("{call sp_getAccountBalance(?)}");
  cs.setString(1, custname);
  ResultSet results = cs.executeQuery();
  // … result set handling
} catch (SQLException se) {
  // … logging and error handling
}

VB an toàn. NET Ví dụ về thủ tục lưu trữ

Ví dụ mã sau đây sử dụng một

//First is an unsafe HQL Statement
Query unsafeHQLQuery = session.createQuery("from Inventory where productID='"+userSuppliedParameter+"'");
//Here is a safe version of the same query using named parameters
Query safeHQLQuery = session.createQuery("from Inventory where productID=:productid");
safeHQLQuery.setParameter("productid", userSuppliedParameter);
5,. NET triển khai giao diện thủ tục được lưu trữ, để thực hiện cùng một truy vấn cơ sở dữ liệu. Thủ tục được lưu trữ
//First is an unsafe HQL Statement
Query unsafeHQLQuery = session.createQuery("from Inventory where productID='"+userSuppliedParameter+"'");
//Here is a safe version of the same query using named parameters
Query safeHQLQuery = session.createQuery("from Inventory where productID=:productid");
safeHQLQuery.setParameter("productid", userSuppliedParameter);
4 sẽ phải được xác định trước trong cơ sở dữ liệu và triển khai chức năng tương tự như truy vấn được xác định ở trên

 Try
   Dim command As SqlCommand = new SqlCommand("sp_getAccountBalance", connection)
   command.CommandType = CommandType.StoredProcedure
   command.Parameters.Add(new SqlParameter("@CustomerName", CustomerName.Text))
   Dim reader As SqlDataReader = command.ExecuteReader()
   '...
 Catch se As SqlException
   'error handling
 End Try

Lựa chọn phòng thủ 3. Xác thực đầu vào danh sách cho phép

Các phần khác nhau của truy vấn SQL không phải là vị trí hợp pháp để sử dụng các biến liên kết, chẳng hạn như tên của bảng hoặc cột và chỉ báo thứ tự sắp xếp (ASC hoặc DESC). Trong những tình huống như vậy, xác thực đầu vào hoặc thiết kế lại truy vấn là biện pháp bảo vệ thích hợp nhất. Đối với tên của bảng hoặc cột, lý tưởng nhất là những giá trị đó đến từ mã chứ không phải từ tham số người dùng

Nhưng nếu các giá trị tham số người dùng được sử dụng để nhắm mục tiêu các tên bảng và tên cột khác nhau, thì các giá trị tham số đó sẽ được ánh xạ tới các tên cột hoặc bảng hợp pháp/dự kiến ​​để đảm bảo thông tin đầu vào chưa được xác thực của người dùng không kết thúc trong truy vấn. Xin lưu ý, đây là một triệu chứng của thiết kế kém và nên xem xét viết lại toàn bộ nếu thời gian cho phép

Dưới đây là một ví dụ về xác thực tên bảng

String tableName;
switch(PARAM):
  case "Value1": tableName = "fooTable";
                 break;
  case "Value2": tableName = "barTable";
                 break;
  ...
  default      : throw new InputValidationException("unexpected value provided"
                                                  + " for table name");

Sau đó,

//First is an unsafe HQL Statement
Query unsafeHQLQuery = session.createQuery("from Inventory where productID='"+userSuppliedParameter+"'");
//Here is a safe version of the same query using named parameters
Query safeHQLQuery = session.createQuery("from Inventory where productID=:productid");
safeHQLQuery.setParameter("productid", userSuppliedParameter);
7 có thể được thêm trực tiếp vào truy vấn SQL vì nó hiện được biết là một trong các giá trị hợp pháp và được mong đợi cho tên bảng trong truy vấn này. Hãy nhớ rằng các chức năng xác thực bảng chung có thể dẫn đến mất dữ liệu vì tên bảng được sử dụng trong các truy vấn mà chúng không được mong đợi

Đối với những thứ đơn giản như thứ tự sắp xếp, sẽ tốt nhất nếu đầu vào do người dùng cung cấp được chuyển đổi thành boolean và sau đó boolean đó được sử dụng để chọn giá trị an toàn để thêm vào truy vấn. Đây là một nhu cầu rất chuẩn trong việc tạo truy vấn động

Ví dụ

public String someMethod(boolean sortOrder) {
 String SQLquery = "some SQL ... order by Salary " + (sortOrder ? "ASC" : "DESC");`
 ...

Bất cứ lúc nào đầu vào của người dùng có thể được chuyển đổi thành không phải Chuỗi, như ngày, số, boolean, kiểu liệt kê, v.v. trước khi nó được thêm vào một truy vấn hoặc được sử dụng để chọn một giá trị để nối thêm vào truy vấn, điều này đảm bảo an toàn khi làm như vậy

Xác thực đầu vào cũng được khuyến nghị làm biện pháp bảo vệ phụ trong TẤT CẢ các trường hợp, ngay cả khi sử dụng các biến liên kết như sẽ được thảo luận sau trong bài viết này. Các kỹ thuật khác về cách triển khai xác thực đầu vào mạnh được mô tả trong Bảng gian lận xác thực đầu vào

Lựa chọn phòng thủ 4. Thoát khỏi tất cả đầu vào do người dùng cung cấp

Kỹ thuật này chỉ nên được sử dụng như là phương sách cuối cùng, khi không có cách nào ở trên khả thi. Xác thực đầu vào có lẽ là một lựa chọn tốt hơn vì phương pháp này yếu so với các biện pháp bảo vệ khác và chúng tôi không thể đảm bảo rằng nó sẽ ngăn chặn tất cả các lần Tiêm SQL trong mọi tình huống

Kỹ thuật này là để thoát đầu vào của người dùng trước khi đưa nó vào một truy vấn. Nó rất cụ thể về cơ sở dữ liệu trong quá trình triển khai. Chúng tôi thường chỉ khuyến nghị trang bị thêm mã kế thừa khi triển khai xác thực đầu vào không hiệu quả về mặt chi phí. Các ứng dụng được xây dựng từ đầu hoặc các ứng dụng yêu cầu khả năng chấp nhận rủi ro thấp nên được xây dựng hoặc viết lại bằng truy vấn được tham số hóa, thủ tục được lưu trữ hoặc một số loại Trình ánh xạ quan hệ đối tượng (ORM) giúp xây dựng truy vấn cho bạn

Kỹ thuật này hoạt động như thế này. Mỗi DBMS hỗ trợ một hoặc nhiều sơ đồ thoát ký tự dành riêng cho một số loại truy vấn. Sau đó, nếu bạn thoát khỏi tất cả đầu vào do người dùng cung cấp bằng cách sử dụng sơ đồ thoát thích hợp cho cơ sở dữ liệu bạn đang sử dụng, DBMS sẽ không nhầm lẫn đầu vào đó với mã SQL do nhà phát triển viết, do đó tránh được mọi lỗ hổng SQL injection có thể xảy ra

API bảo mật doanh nghiệp OWASP (ESAPI) là thư viện kiểm soát bảo mật ứng dụng web, mã nguồn mở, miễn phí giúp lập trình viên viết các ứng dụng có rủi ro thấp hơn dễ dàng hơn. Các thư viện ESAPI được thiết kế để giúp các lập trình viên dễ dàng trang bị thêm bảo mật cho các ứng dụng hiện có. Các thư viện ESAPI cũng đóng vai trò là nền tảng vững chắc cho sự phát triển mới

  • Chi tiết đầy đủ về ESAPI có tại đây trên OWASP
  • javadoc cho ESAPI 2. x (Cũ) có sẵn. Mã này đã được chuyển sang GitHub vào tháng 11 năm 2014
  • ESAPI kế thừa cho Java tại GitHub giúp hiểu việc sử dụng nó hiện tại khi Javadoc dường như không đủ
  • Một lần thử ESAPI khác cho Java GitHub có các cách tiếp cận khác và không có thử nghiệm hoặc codec cụ thể nào

Để tìm javadoc dành riêng cho bộ mã hóa cơ sở dữ liệu, hãy nhấp vào lớp

//First is an unsafe HQL Statement
Query unsafeHQLQuery = session.createQuery("from Inventory where productID='"+userSuppliedParameter+"'");
//Here is a safe version of the same query using named parameters
Query safeHQLQuery = session.createQuery("from Inventory where productID=:productid");
safeHQLQuery.setParameter("productid", userSuppliedParameter);
8 ở phía bên tay trái. Có rất nhiều Codec được triển khai. Hai codec dành riêng cho Cơ sở dữ liệu là
//First is an unsafe HQL Statement
Query unsafeHQLQuery = session.createQuery("from Inventory where productID='"+userSuppliedParameter+"'");
//Here is a safe version of the same query using named parameters
Query safeHQLQuery = session.createQuery("from Inventory where productID=:productid");
safeHQLQuery.setParameter("productid", userSuppliedParameter);
9 và
// This should REALLY be validated
String custname = request.getParameter("customerName");
try {
  CallableStatement cs = connection.prepareCall("{call sp_getAccountBalance(?)}");
  cs.setString(1, custname);
  ResultSet results = cs.executeQuery();
  // … result set handling
} catch (SQLException se) {
  // … logging and error handling
}
0

Chỉ cần nhấp vào tên của họ trong

// This should REALLY be validated
String custname = request.getParameter("customerName");
try {
  CallableStatement cs = connection.prepareCall("{call sp_getAccountBalance(?)}");
  cs.setString(1, custname);
  ResultSet results = cs.executeQuery();
  // … result set handling
} catch (SQLException se) {
  // … logging and error handling
}
1 ở đầu trang Codec giao diện

Tại thời điểm này, ESAPI hiện có bộ mã hóa cơ sở dữ liệu cho

  • tiên tri
  • MySQL (Cả chế độ ANSI và chế độ gốc đều được hỗ trợ)

Bộ mã hóa cơ sở dữ liệu sắp ra mắt cho

  • Máy chủ SQL
  • PostgreSQL

Nếu bộ mã hóa cơ sở dữ liệu của bạn bị thiếu, vui lòng cho chúng tôi biết

Cơ sở dữ liệu cụ thể thoát chi tiết

Nếu bạn muốn xây dựng quy trình thoát của riêng mình, đây là chi tiết thoát cho từng cơ sở dữ liệu mà chúng tôi đã phát triển Bộ mã hóa ESAPI cho

  • tiên tri
  • Máy chủ SQL
  • DB2
Thoát khỏi Oracle

Thông tin này dựa trên

Thoát truy vấn động¶

Để sử dụng codec cơ sở dữ liệu ESAPI khá đơn giản. Một ví dụ về Oracle trông giống như

ESAPI.encoder().encodeForSQL( new OracleCodec(), queryparam );

Vì vậy, nếu bạn có một truy vấn Động hiện có đang được tạo trong mã của bạn, truy vấn này sẽ được chuyển tới Oracle trông như thế này

String query = "SELECT user_id FROM user_data WHERE user_name = '"
              + req.getParameter("userID")
              + "' and user_password = '" + req.getParameter("pwd") +"'";
try {
    Statement statement = connection.createStatement(  );
    ResultSet results = statement.executeQuery( query );
}

Bạn sẽ viết lại dòng đầu tiên như thế này

// This should REALLY be validated too
String custname = request.getParameter("customerName");
// Perform input validation to detect attacks
String query = "SELECT account_balance FROM user_data WHERE user_name = ? ";
PreparedStatement pstmt = connection.prepareStatement( query );
pstmt.setString( 1, custname);
ResultSet results = pstmt.executeQuery( );
0

Và bây giờ nó sẽ an toàn trước SQL injection, bất kể đầu vào được cung cấp là gì

Để có khả năng đọc mã tối đa, bạn cũng có thể xây dựng mã

// This should REALLY be validated
String custname = request.getParameter("customerName");
try {
  CallableStatement cs = connection.prepareCall("{call sp_getAccountBalance(?)}");
  cs.setString(1, custname);
  ResultSet results = cs.executeQuery();
  // … result set handling
} catch (SQLException se) {
  // … logging and error handling
}
2 của riêng mình

// This should REALLY be validated too
String custname = request.getParameter("customerName");
// Perform input validation to detect attacks
String query = "SELECT account_balance FROM user_data WHERE user_name = ? ";
PreparedStatement pstmt = connection.prepareStatement( query );
pstmt.setString( 1, custname);
ResultSet results = pstmt.executeQuery( );
1

Với loại giải pháp này, bạn chỉ cần gói mỗi tham số do người dùng cung cấp được chuyển vào một cuộc gọi

// This should REALLY be validated
String custname = request.getParameter("customerName");
try {
  CallableStatement cs = connection.prepareCall("{call sp_getAccountBalance(?)}");
  cs.setString(1, custname);
  ResultSet results = cs.executeQuery();
  // … result set handling
} catch (SQLException se) {
  // … logging and error handling
}
3 hoặc bất cứ thứ gì bạn đặt tên cho cuộc gọi và bạn sẽ hoàn thành

Tắt thay thế ký tự¶

Sử dụng

// This should REALLY be validated
String custname = request.getParameter("customerName");
try {
  CallableStatement cs = connection.prepareCall("{call sp_getAccountBalance(?)}");
  cs.setString(1, custname);
  ResultSet results = cs.executeQuery();
  // … result set handling
} catch (SQLException se) {
  // … logging and error handling
}
4 hoặc
// This should REALLY be validated
String custname = request.getParameter("customerName");
try {
  CallableStatement cs = connection.prepareCall("{call sp_getAccountBalance(?)}");
  cs.setString(1, custname);
  ResultSet results = cs.executeQuery();
  // … result set handling
} catch (SQLException se) {
  // … logging and error handling
}
5 để đảm bảo tắt thay thế ký tự tự động. Nếu tính năng thay thế ký tự này được bật, ký tự & sẽ được coi như một tiền tố biến SQLPlus có thể cho phép kẻ tấn công truy xuất dữ liệu riêng tư

Xem và tại đây để biết thêm thông tin

Thoát các ký tự Đại diện trong Mệnh đề Thích¶

Từ khóa

// This should REALLY be validated
String custname = request.getParameter("customerName");
try {
  CallableStatement cs = connection.prepareCall("{call sp_getAccountBalance(?)}");
  cs.setString(1, custname);
  ResultSet results = cs.executeQuery();
  // … result set handling
} catch (SQLException se) {
  // … logging and error handling
}
6 cho phép tìm kiếm quét văn bản. Trong Oracle, ký tự gạch dưới
// This should REALLY be validated
String custname = request.getParameter("customerName");
try {
  CallableStatement cs = connection.prepareCall("{call sp_getAccountBalance(?)}");
  cs.setString(1, custname);
  ResultSet results = cs.executeQuery();
  // … result set handling
} catch (SQLException se) {
  // … logging and error handling
}
7 chỉ khớp với một ký tự, trong khi dấu và
// This should REALLY be validated
String custname = request.getParameter("customerName");
try {
  CallableStatement cs = connection.prepareCall("{call sp_getAccountBalance(?)}");
  cs.setString(1, custname);
  ResultSet results = cs.executeQuery();
  // … result set handling
} catch (SQLException se) {
  // … logging and error handling
}
8 được sử dụng để khớp với 0 hoặc nhiều lần xuất hiện của bất kỳ ký tự nào. Các ký tự này phải được thoát trong tiêu chí mệnh đề THÍCH

Ví dụ

// This should REALLY be validated too
String custname = request.getParameter("customerName");
// Perform input validation to detect attacks
String query = "SELECT account_balance FROM user_data WHERE user_name = ? ";
PreparedStatement pstmt = connection.prepareStatement( query );
pstmt.setString( 1, custname);
ResultSet results = pstmt.executeQuery( );
2

Oracle 10g thoát¶

Một giải pháp thay thế cho Oracle 10g trở lên là đặt

// This should REALLY be validated
String custname = request.getParameter("customerName");
try {
  CallableStatement cs = connection.prepareCall("{call sp_getAccountBalance(?)}");
  cs.setString(1, custname);
  ResultSet results = cs.executeQuery();
  // … result set handling
} catch (SQLException se) {
  // … logging and error handling
}
9 và
 Try
   Dim command As SqlCommand = new SqlCommand("sp_getAccountBalance", connection)
   command.CommandType = CommandType.StoredProcedure
   command.Parameters.Add(new SqlParameter("@CustomerName", CustomerName.Text))
   Dim reader As SqlDataReader = command.ExecuteReader()
   '...
 Catch se As SqlException
   'error handling
 End Try
0 xung quanh chuỗi để thoát khỏi toàn bộ chuỗi. Tuy nhiên, bạn phải cẩn thận rằng không có ký tự
 Try
   Dim command As SqlCommand = new SqlCommand("sp_getAccountBalance", connection)
   command.CommandType = CommandType.StoredProcedure
   command.Parameters.Add(new SqlParameter("@CustomerName", CustomerName.Text))
   Dim reader As SqlDataReader = command.ExecuteReader()
   '...
 Catch se As SqlException
   'error handling
 End Try
0 nào trong chuỗi. Bạn phải tìm kiếm những thứ này và nếu có, thì bạn phải thay thế nó bằng
 Try
   Dim command As SqlCommand = new SqlCommand("sp_getAccountBalance", connection)
   command.CommandType = CommandType.StoredProcedure
   command.Parameters.Add(new SqlParameter("@CustomerName", CustomerName.Text))
   Dim reader As SqlDataReader = command.ExecuteReader()
   '...
 Catch se As SqlException
   'error handling
 End Try
2. Nếu không, nhân vật đó sẽ kết thúc quá trình trốn thoát sớm và có thể gây ra lỗ hổng

MySQL thoát

MySQL hỗ trợ hai chế độ thoát

  1.  Try
       Dim command As SqlCommand = new SqlCommand("sp_getAccountBalance", connection)
       command.CommandType = CommandType.StoredProcedure
       command.Parameters.Add(new SqlParameter("@CustomerName", CustomerName.Text))
       Dim reader As SqlDataReader = command.ExecuteReader()
       '...
     Catch se As SqlException
       'error handling
     End Try
    
    3 Chế độ SQL và một chế độ tắt chế độ này mà chúng tôi gọi là
  2. Chế độ
     Try
       Dim command As SqlCommand = new SqlCommand("sp_getAccountBalance", connection)
       command.CommandType = CommandType.StoredProcedure
       command.Parameters.Add(new SqlParameter("@CustomerName", CustomerName.Text))
       Dim reader As SqlDataReader = command.ExecuteReader()
       '...
     Catch se As SqlException
       'error handling
     End Try
    
    4

Chế độ

 Try
   Dim command As SqlCommand = new SqlCommand("sp_getAccountBalance", connection)
   command.CommandType = CommandType.StoredProcedure
   command.Parameters.Add(new SqlParameter("@CustomerName", CustomerName.Text))
   Dim reader As SqlDataReader = command.ExecuteReader()
   '...
 Catch se As SqlException
   'error handling
 End Try
5. Chỉ cần mã hóa tất cả các ký tự
 Try
   Dim command As SqlCommand = new SqlCommand("sp_getAccountBalance", connection)
   command.CommandType = CommandType.StoredProcedure
   command.Parameters.Add(new SqlParameter("@CustomerName", CustomerName.Text))
   Dim reader As SqlDataReader = command.ExecuteReader()
   '...
 Catch se As SqlException
   'error handling
 End Try
6 (đánh dấu một lần) bằng
 Try
   Dim command As SqlCommand = new SqlCommand("sp_getAccountBalance", connection)
   command.CommandType = CommandType.StoredProcedure
   command.Parameters.Add(new SqlParameter("@CustomerName", CustomerName.Text))
   Dim reader As SqlDataReader = command.ExecuteReader()
   '...
 Catch se As SqlException
   'error handling
 End Try
7 (hai dấu tích đơn)

Chế độ

 Try
   Dim command As SqlCommand = new SqlCommand("sp_getAccountBalance", connection)
   command.CommandType = CommandType.StoredProcedure
   command.Parameters.Add(new SqlParameter("@CustomerName", CustomerName.Text))
   Dim reader As SqlDataReader = command.ExecuteReader()
   '...
 Catch se As SqlException
   'error handling
 End Try
4, hãy làm như sau

// This should REALLY be validated too
String custname = request.getParameter("customerName");
// Perform input validation to detect attacks
String query = "SELECT account_balance FROM user_data WHERE user_name = ? ";
PreparedStatement pstmt = connection.prepareStatement( query );
pstmt.setString( 1, custname);
ResultSet results = pstmt.executeQuery( );
3

Thông tin này dựa trên thông tin ký tự MySQL Escape

Máy chủ SQL thoát

Chúng tôi chưa triển khai quy trình thoát SQL Server, nhưng sau đây có các gợi ý hay và liên kết đến các bài viết mô tả cách ngăn chặn các cuộc tấn công SQL injection trên máy chủ SQL, xem tại đây

Thoát khỏi DB2

Thông tin này dựa trên các ký tự đặc biệt của DB2 WebQuery cũng như một số thông tin từ trình điều khiển JDBC DB2 của Oracle

Thông tin liên quan đến sự khác biệt giữa một số trình điều khiển DB2 Universal

Mã hóa hex tất cả đầu vào

Một trường hợp thoát hơi đặc biệt là quá trình mã hóa hex toàn bộ chuỗi nhận được từ người dùng (điều này có thể được coi là thoát mọi ký tự). Ứng dụng web nên mã hóa hex đầu vào của người dùng trước khi đưa nó vào câu lệnh SQL. Câu lệnh SQL nên tính đến thực tế này và theo đó so sánh dữ liệu

Ví dụ: nếu chúng ta phải tra cứu một bản ghi khớp với sessionID và người dùng đã truyền chuỗi abc123 làm ID phiên, thì câu lệnh select sẽ là

// This should REALLY be validated too
String custname = request.getParameter("customerName");
// Perform input validation to detect attacks
String query = "SELECT account_balance FROM user_data WHERE user_name = ? ";
PreparedStatement pstmt = connection.prepareStatement( query );
pstmt.setString( 1, custname);
ResultSet results = pstmt.executeQuery( );
4

 Try
   Dim command As SqlCommand = new SqlCommand("sp_getAccountBalance", connection)
   command.CommandType = CommandType.StoredProcedure
   command.Parameters.Add(new SqlParameter("@CustomerName", CustomerName.Text))
   Dim reader As SqlDataReader = command.ExecuteReader()
   '...
 Catch se As SqlException
   'error handling
 End Try
9 nên được thay thế bằng cơ sở cụ thể cho cơ sở dữ liệu đang được sử dụng. Chuỗi 606162313233 là phiên bản mã hóa hex của chuỗi nhận được từ người dùng (nó là chuỗi giá trị hex của mã ASCII/UTF-8 của dữ liệu người dùng)

Nếu kẻ tấn công truyền một chuỗi chứa ký tự trích dẫn đơn, sau đó là nỗ lực chèn mã SQL, thì câu lệnh SQL được xây dựng sẽ trông giống như

// This should REALLY be validated too
String custname = request.getParameter("customerName");
// Perform input validation to detect attacks
String query = "SELECT account_balance FROM user_data WHERE user_name = ? ";
PreparedStatement pstmt = connection.prepareStatement( query );
pstmt.setString( 1, custname);
ResultSet results = pstmt.executeQuery( );
5

String tableName;
switch(PARAM):
  case "Value1": tableName = "fooTable";
                 break;
  case "Value2": tableName = "barTable";
                 break;
  ...
  default      : throw new InputValidationException("unexpected value provided"
                                                  + " for table name");
0 là mã ASCII (ở dạng hex) của trích dẫn đơn, được mã hóa hex đơn giản giống như bất kỳ ký tự nào khác trong chuỗi. SQL kết quả chỉ có thể chứa các chữ số và chữ cái
String tableName;
switch(PARAM):
  case "Value1": tableName = "fooTable";
                 break;
  case "Value2": tableName = "barTable";
                 break;
  ...
  default      : throw new InputValidationException("unexpected value provided"
                                                  + " for table name");
1 đến
String tableName;
switch(PARAM):
  case "Value1": tableName = "fooTable";
                 break;
  case "Value2": tableName = "barTable";
                 break;
  ...
  default      : throw new InputValidationException("unexpected value provided"
                                                  + " for table name");
2 và không bao giờ có bất kỳ ký tự đặc biệt nào có thể kích hoạt SQL injection

Thoát SQLi trong PHP

Sử dụng câu lệnh đã chuẩn bị và truy vấn được tham số hóa. Đây là các câu lệnh SQL được máy chủ cơ sở dữ liệu gửi đến và phân tích cú pháp riêng biệt với bất kỳ tham số nào. Bằng cách này, kẻ tấn công không thể tiêm SQL độc hại

Về cơ bản, bạn có hai lựa chọn để đạt được điều này

  1. Sử dụng PDO (đối với mọi trình điều khiển cơ sở dữ liệu được hỗ trợ)

// This should REALLY be validated too
String custname = request.getParameter("customerName");
// Perform input validation to detect attacks
String query = "SELECT account_balance FROM user_data WHERE user_name = ? ";
PreparedStatement pstmt = connection.prepareStatement( query );
pstmt.setString( 1, custname);
ResultSet results = pstmt.executeQuery( );
6

  1. Sử dụng MySQLi (dành cho MySQL)

// This should REALLY be validated too
String custname = request.getParameter("customerName");
// Perform input validation to detect attacks
String query = "SELECT account_balance FROM user_data WHERE user_name = ? ";
PreparedStatement pstmt = connection.prepareStatement( query );
pstmt.setString( 1, custname);
ResultSet results = pstmt.executeQuery( );
7

PDO là tùy chọn phổ quát. Nếu bạn đang kết nối với cơ sở dữ liệu không phải MySQL, bạn có thể tham khảo tùy chọn thứ hai dành riêng cho trình điều khiển (e. g. pg_prepare() và pg_execute() cho PostgreSQL)

phòng thủ bổ sung

Ngoài việc áp dụng một trong bốn biện pháp phòng thủ chính, chúng tôi cũng khuyên bạn nên áp dụng tất cả các biện pháp phòng thủ bổ sung này để cung cấp khả năng phòng thủ có chiều sâu. Những phòng thủ bổ sung này là

  • Đặc quyền nhất
  • Xác thực đầu vào danh sách cho phép

Đặc quyền nhất

Để giảm thiểu thiệt hại tiềm ẩn của một cuộc tấn công SQL injection thành công, bạn nên giảm thiểu các đặc quyền được gán cho mọi tài khoản cơ sở dữ liệu trong môi trường của mình. Không gán quyền truy cập loại DBA hoặc quản trị viên cho tài khoản ứng dụng của bạn. Chúng tôi hiểu rằng điều này rất dễ dàng và mọi thứ chỉ "hoạt động" khi bạn làm theo cách này, nhưng nó rất nguy hiểm

Bắt đầu từ đầu để xác định những quyền truy cập mà tài khoản ứng dụng của bạn yêu cầu, thay vì cố gắng tìm ra những quyền truy cập nào bạn cần lấy đi. Đảm bảo rằng các tài khoản chỉ cần quyền truy cập đọc chỉ được cấp quyền truy cập đọc vào các bảng mà họ cần quyền truy cập

Nếu một tài khoản chỉ cần quyền truy cập vào các phần của bảng, hãy xem xét việc tạo chế độ xem giới hạn quyền truy cập vào phần dữ liệu đó và chỉ định quyền truy cập của tài khoản vào chế độ xem thay vì bảng bên dưới. Hiếm khi cấp quyền tạo hoặc xóa quyền truy cập vào tài khoản cơ sở dữ liệu

Nếu bạn áp dụng chính sách trong đó bạn sử dụng các thủ tục được lưu trữ ở mọi nơi và không cho phép các tài khoản ứng dụng thực hiện trực tiếp các truy vấn của riêng họ, thì hãy hạn chế các tài khoản đó chỉ có thể thực hiện các thủ tục được lưu trữ mà họ cần. Không cấp cho họ bất kỳ quyền nào trực tiếp đối với các bảng trong cơ sở dữ liệu

SQL injection không phải là mối đe dọa duy nhất đối với dữ liệu cơ sở dữ liệu của bạn. Những kẻ tấn công có thể chỉ cần thay đổi các giá trị tham số từ một trong các giá trị hợp pháp mà chúng được cung cấp thành một giá trị không được phép đối với chúng, nhưng bản thân ứng dụng có thể được phép truy cập. Do đó, việc giảm thiểu các đặc quyền được cấp cho ứng dụng của bạn sẽ làm giảm khả năng xảy ra các nỗ lực truy cập trái phép như vậy, ngay cả khi kẻ tấn công không cố gắng sử dụng SQL injection như một phần trong quá trình khai thác của chúng.

Trong khi bạn đang ở đó, bạn nên giảm thiểu các đặc quyền của tài khoản hệ điều hành mà DBMS chạy bên dưới. Đừng chạy DBMS của bạn với quyền root hoặc hệ thống. Hầu hết các DBMS chạy ra khỏi hộp với một tài khoản hệ thống rất mạnh. Ví dụ: mặc định MySQL chạy dưới dạng hệ thống trên Windows. Thay đổi tài khoản HĐH của DBMS thành thứ gì đó phù hợp hơn, với các đặc quyền bị hạn chế

Nhiều người dùng DB

Các nhà thiết kế ứng dụng web nên tránh sử dụng cùng một tài khoản chủ sở hữu/quản trị viên trong các ứng dụng web để kết nối với cơ sở dữ liệu. Người dùng DB khác nhau nên được sử dụng cho các ứng dụng web khác nhau

Nói chung, mỗi ứng dụng web riêng biệt yêu cầu quyền truy cập vào cơ sở dữ liệu phải có tài khoản người dùng cơ sở dữ liệu được chỉ định mà ứng dụng sẽ sử dụng để kết nối với DB. Bằng cách đó, người thiết kế ứng dụng có thể có mức độ chi tiết tốt trong kiểm soát truy cập, do đó giảm các đặc quyền càng nhiều càng tốt. Sau đó, mỗi người dùng DB sẽ chỉ có quyền truy cập được chọn vào những gì họ cần và quyền ghi khi cần

Ví dụ: trang đăng nhập yêu cầu quyền truy cập đọc vào trường tên người dùng và mật khẩu của bảng, nhưng không có quyền ghi dưới bất kỳ hình thức nào (không chèn, cập nhật hoặc xóa). Tuy nhiên, trang đăng ký chắc chắn yêu cầu chèn đặc quyền vào bảng đó;

Lượt xem

Bạn có thể sử dụng các dạng xem SQL để tăng thêm mức độ chi tiết của quyền truy cập bằng cách giới hạn quyền truy cập đọc đối với các trường cụ thể của bảng hoặc các liên kết của bảng. Nó có khả năng có thêm lợi ích. ví dụ: giả sử rằng hệ thống được yêu cầu (có thể do một số yêu cầu pháp lý cụ thể) để lưu trữ mật khẩu của người dùng, thay vì mật khẩu được băm muối

Người thiết kế có thể sử dụng các khung nhìn để bù đắp cho hạn chế này; . Bất kỳ cuộc tấn công SQL injection nào thành công trong việc đánh cắp thông tin DB sẽ bị hạn chế đánh cắp hàm băm của mật khẩu (thậm chí có thể là hàm băm có khóa), vì không người dùng DB nào cho bất kỳ ứng dụng web nào có quyền truy cập vào chính bảng đó

Xác thực đầu vào danh sách cho phép

Ngoài việc là phòng thủ chính khi không thể làm gì khác (e. g. , khi một biến liên kết không hợp pháp), xác thực đầu vào cũng có thể là biện pháp bảo vệ thứ cấp được sử dụng để phát hiện đầu vào trái phép trước khi nó được chuyển đến truy vấn SQL. Để biết thêm thông tin, vui lòng xem Bảng gian lận xác thực đầu vào. Tiếp tục thận trọng ở đây. Dữ liệu đã được xác thực không nhất thiết phải an toàn để chèn vào truy vấn SQL thông qua xây dựng chuỗi

Những bài viết liên quan

Bảng cheat tấn công SQL injection

Các bài viết sau đây mô tả cách khai thác các loại Lỗ hổng SQL injection khác nhau trên các nền tảng khác nhau mà bài viết này được tạo ra để giúp bạn tránh