2012-05-08 19 views
6

tôi đang làm việc trên một dự án mà có một đoạn mã như hình dưới đây:Làm thế nào để tránh "Security - Một tuyên bố chuẩn bị được tạo ra từ một String nonconstant" FindBugs Warning

String sql = "SELECT MAX(" + columnName + ") FROM " + tableName;     
PreparedStatement ps = connection.prepareStatement(sql); 

Có cách nào mà Tôi có thể thay đổi mã này để FindBugs ngừng cung cấp cho tôi một cảnh báo "An ninh - Một tuyên bố chuẩn bị được tạo ra từ một chuỗi không liên quan" là ?

Hãy giả sử rằng mã này an toàn liên quan đến SQL INJECTION vì tôi có thể kiểm soát ở nơi khác trong mã có thể là giá trị cho "tableName" và "columnName" (chúng không đến trực tiếp từ đầu vào của người dùng).

Trả lời

3

Không ghép nối sql Chuỗi bởi +. Bạn có thể sử dụng

String sql = String.format("SELECT MAX(%s) FROM %s ", columnName, tableName); 

Đây là chậm hơn so với ghép chuỗi để bạn nên khởi tạo static thì đây không phải là vấn đề.

Tôi nghĩ sử dụng StringBuilder cũng sẽ khắc phục cảnh báo này.

Một cách khác bạn có thể tránh cảnh báo này là thêm @SuppressWarnings("SQL_PREPARED_STATEMENT_GENERATED_FROM_NONCONSTANT_STRING") phía trên chuỗi đó (hoặc phương pháp/hoặc lớp học).

Bạn cũng có thể sử dụng Filter File để xác định các quy tắc cần được loại trừ.

+0

Xin chào người dùng714965, cảm ơn bạn đã trả lời. Tôi có những lần xuất hiện khác của cảnh báo này bằng cách sử dụng StringBuilder, do đó nó không hoạt động. Chú thích hoạt động (rất tốt để làm rõ cho người đọc khác rằng tên đầy đủ của nó là @ edu.umd.cs.findbugs.annotations.SuppressWarnings). Bây giờ tôi phải quyết định nếu tôi muốn lib FindBugs trong dự án của tôi hay không. Cảm ơn một lần nữa. – ederribeiro

+0

@ederribeiro: Sự phụ thuộc vào FindBugs từ dự án của bạn có thể không phải là điều tốt nhất bạn nói đúng. Trong câu trả lời ban đầu của tôi, tôi đã bỏ lỡ một điểm, xin vui lòng xem đoạn cuối. – Kai

+2

Điều này giải quyết vấn đề cụ thể này bởi vì OP chắc chắn rằng mã của mình được an toàn khỏi SQL INJECTION. Nhưng đó là lỗi dễ bị và do đó một thực hành xấu nói chung. Các câu lệnh được chuẩn bị với các tham số là cách để đi. Sẽ không bỏ phiếu tiêu cực vì nó thực sự giải quyết các câu hỏi nhưng tôi khuyên không nên làm theo cách đó. –

1

Hãy thử sử dụng sau đây ...

private static final String SQL = "SELECT MAX(%s) FROM %s"; 

Và sau đó sử dụng một String.format() gọi khi bạn sử dụng nó ...

PreparedStatement ps = connection.prepareStatement(String.format(sql,columnName,tableName)); 

Nếu điều đó không giải quyết được vấn đề , bạn luôn có thể bỏ qua kiểm tra đó; tắt nó đi trong cấu hình FindBugs của bạn.

Nếu điều đó không hoạt động (hoặc không phải là một tùy chọn), một số IDE (như IntelliJ) cũng sẽ cho phép bạn chặn cảnh báo bằng chú thích hoặc chú thích được định dạng đặc biệt.

+0

Xin chào Jesse, cảm ơn bạn đã trả lời. Tôi đã cố gắng làm như bạn nói nhưng tiếc là nó không hoạt động. Đề nghị cuối cùng của bạn, giống như @ user714965 đã đề cập, thực hiện thủ thuật. Bây giờ tôi phải quyết định nếu tôi muốn trả giá của việc có FindBugs lib trong dự án của tôi chỉ để thoát khỏi cảnh báo. – ederribeiro

1

Cả String.format lẫn StringBuilder (hoặc StringBuffer) đều không hỗ trợ tôi.

Giải pháp là "prepareStatement" cách ly:

private PreparedStatement prepareStatement(Connection conn, String sql) throws SQLException { 
    return conn.prepareStatement(sql); 
} 
+0

Điều đó cũng không giúp tôi. – Lenymm

4
private static final String SQL = "SELECT MAX(?) FROM ?"; 
PreparedStatement ps = connection.prepareStatement(sql); 
ps.preparedStatement.setInt(1,columnName); 
ps.preparedStatement.setString(2,tableName); 

nếu bạn đang sử dụng tuyên bố chuẩn bị, sau đó trong tham số phải là một chuỗi thức và các thông số nên được bổ sung sau sử dụng setInt, setString phương pháp.

điều này sẽ giải quyết cảnh báo tìm kiếm.

+1

bạn đã thực hiện tuyên bố của mình chưa? Tên bảng gắn kết bạn nhận được 'ORA-00903: tên bảng không hợp lệ'. Việc chuyển tên cột hoạt động, nhưng bạn lấy lại tên cột (không phải giá trị cột). Đây là NOGO! –

0

Nếu bạn chắc chắn rằng không có khả năng của SQL injection, sử dụng SuppressFBWarnings chú thích về phương pháp:

@edu.umd.cs.findbugs.annotations.SuppressFBWarnings("SQL_PREPARED_STATEMENT_GENERATED_FROM_NONCONSTANT_STRING") 
1

Có thể sử dụng nối để tạo ra chuỗi của bạn. Làm như vậy không gây ra cảnh báo Bảo mật.Và thích hợp hơn vì lợi ích của sự rõ ràng khi xử lý các câu lệnh SQL dài sẽ được chia nhỏ hơn trên nhiều dòng

Sử dụng các biến để tạo chuỗi là nguyên nhân gây ra cảnh báo bảo mật.

Điều này sẽ gây ra cảnh báo:

String columnName = getName(); 
String tableName = getTableName(); 
final String sql = "SELECT MAX(" + columnName + ") FROM " + tableName; 
PreparedStatement ps = connection.prepareStatement(sql); 

này sẽ không không làm việc:

String columnName = getName(); 
String tableName = getTableName(); 
final String sql = "SELECT MAX(" + "?" + ")" + 
        "FROM " + "?"; 
PreparedStatement ps = connection.prepareStatement(sql); 
ps.setString(1, columnName); 
ps.setString(2, tableName); 

Nó không làm việc vì chuẩn bị phát biểu chỉ cho phép các thông số bị ràng buộc cho "giá trị" bit của Câu lệnh sql.

Đây là giải pháp mà làm việc:

private static final boolean USE_TEST_TABLE = true; 
private static final boolean USE_RESTRICTED_COL = true; 
private static final String TEST_TABLE = "CLIENT_TEST"; 
private static final String PROD_TABLE = "CLIENT"; 
private static final String RESTRICTED_COL ="AGE_COLLATED"; 
private static final String UNRESTRICTED_COL ="AGE"; 

.................... 

final String sql = "SELECT MAX(" + 
     (USE_RESTRICTED_COL ? RESTRICTED_COL : UNRESTRICTED_COL) + ")" + 
     "FROM " + 
     (USE_TEST_TABLE ? TEST_TABLE : PROD_TABLE); 
PreparedStatement ps = connectComun.prepareStatement(sql); 

Nhưng nó chỉ hoạt động nếu bạn phải lựa chọn giữa hai bảng có tên được biết tại thời gian biên dịch. Bạn có thể sử dụng các toán tử bậc ba phức tạp cho hơn 2 trường hợp nhưng sau đó nó trở thành không thể đọc được.

Trường hợp đầu tiên có thể là vấn đề bảo mật nếu getName() hoặc getTableName() lấy tên từ các nguồn không đáng tin cậy.

Có thể xây dựng một câu lệnh SQL an toàn sử dụng các biến nếu các biến đó đã được xác minh trước đó. Đây là trường hợp của bạn, nhưng FindBugs không thể tìm ra. Findbugs không thể biết được những nguồn nào đáng tin cậy hay không.

Nhưng nếu bạn phải sử dụng tên cột hoặc bảng từ người dùng hoặc đầu vào không tin cậy thì không có cách nào xung quanh nó. Bạn phải xác minh chính mình chuỗi đó và bỏ qua cảnh báo Findbugs với bất kỳ phương pháp nào được đề xuất trong các câu trả lời khác.

Kết luận: Không có giải pháp hoàn hảo cho trường hợp chung của câu hỏi này.

+0

Hi @ jose-antonio-dura-olmos cảm ơn đề xuất của bạn nhưng, bạn đã thử chưa? Dường như không thể đặt "siêu dữ liệu" (chẳng hạn như tên bảng hoặc tên cột) bằng cách sử dụng câu lệnh đã chuẩn bị. Tôi đã thử với mysql và h2 không thành công. Ngoài ra còn có một người dùng trong chủ đề này đã thử với Oracle và thất bại là tốt. – ederribeiro

+0

Tôi có mã sản xuất thay đổi tên bảng theo cách này. Tôi chưa kiểm tra mã cụ thể này nhưng tôi sẽ làm như vậy. –

+0

Điều này xảy ra khi nói ra khỏi bộ nhớ. Tôi cần phải lựa chọn giữa hai bảng, một bảng cho sản xuất và một cho thử nghiệm. Nhưng nó không hoạt động theo cách đó vì tên bảng và cột không thể thay đổi; câu trước biên dịch cần phải biết tên bảng và cột được sử dụng để xác minh đúng sintax. Do đó, chúng không thể thay đổi. Tôi đã nhận được một giải pháp mà vẫn cho phép tôi sử dụng nối mà không nhận được cảnh báo. Tôi đã cập nhật câu trả lời của mình với giải pháp đó. –

Các vấn đề liên quan