Tất cả chúng ta đều biết, nếu bất kỳ mã ứng dụng nào được viết kém, thì bất kỳ ai cũng có thể hack thông tin bằng cách sử dụng một thủ thuật nhỏ như SQL Injection. Trong bài đăng này, tôi đưa ra một ví dụ để chứng minh cách SQL Injection có thể dễ bị tấn công vào một ứng dụng và cách bạn có thể ngăn chặn nó.
Trình diễn dựa trên bảng EMP của lược đồ SCOTT. Để tải xuống tập lệnh lược đồ SCOTT, hãy nhấp vào liên kết sau Tải xuống tập lệnh lược đồ Scott.
Một ví dụ để thực hiện SQL Injection
Trong phần này, tôi đưa ra một ví dụ về thủ tục được lưu trữ PL / SQL sẽ chấp nhận một số nhân viên tham số là (p_empno) để hiển thị mức lương cho nhân viên đó. Trong mã, tôi đang sử dụng nối giá trị tham số (p_empno) đó trong chuỗi câu lệnh SQL cho REF CURSOR, điều này không được khuyến nghị và sẽ là nguyên nhân của SQL Injection thành công. Dưới đây là quy trình:
CREATE OR REPLACE PROCEDURE PRC_GET_EMP_SAL (p_empno VARCHAR2) IS --Declare a ref cursor and local variables-- TYPE C IS REF CURSOR; CUR_EMP C; L_ENAME VARCHAR2 (100); L_SAL NUMBER; L_STMT VARCHAR2 (4000); BEGIN --Open the ref cursor for a Dynamic SELECT statement-- L_STMT := 'SELECT ename, sal FROM emp WHERE empno = ''' || p_empno || ''''; OPEN CUR_EMP FOR L_STMT; LOOP --Fetch the result set and print the result set-- FETCH CUR_EMP INTO L_ENAME, L_SAL; EXIT WHEN CUR_EMP%NOTFOUND; DBMS_OUTPUT.PUT_LINE (L_ENAME || ' -- ' || L_SAL); END LOOP; CLOSE CUR_EMP; END; /
Bây giờ chúng tôi sẽ kiểm tra quy trình trên một cách bình thường bằng cách chuyển một số nhân viên.
Kiểm tra
SET SERVEROUTPUT ON; BEGIN prc_get_emp_sal ('7566'); END; /
Đầu ra
JONES -- 27706.89 PL/SQL procedure successfully completed.
Cho đến bây giờ mọi thứ vẫn ổn. Bởi vì chúng tôi đã gọi một cách chính xác thủ tục. Bây giờ chúng ta sẽ xem cách chúng ta có thể hack quy trình trên bằng cách sử dụng thủ thuật SQL Injection để lấy lương của tất cả nhân viên. Có lẽ đôi khi bạn cũng muốn làm điều này. Đùa!
Kiểm tra bằng SQL Injection
SET SERVEROUTPUT ON; BEGIN prc_get_emp_sal ('X'' OR ''1''= ''1'); END; /
Đầu ra Chèn SQL thành công
WARD -- 11641.56 JONES -- 27706.89 MARTIN -- 11641.56 BLAKE -- 26542.7 CLARK -- 22817.41 SCOTT -- 83819.06 KING -- 46566.18 TURNER -- 13969.85 ADAMS -- 10244.6 JAMES -- 8847.64 FORD -- 27939.74 MILLER -- 12107.2 PL/SQL procedure successfully completed.
Chà, bây giờ bạn có thể xem mức lương của mọi nhân viên khi sử dụng thủ thuật SQL Injection này. Chỉ cần tưởng tượng, bạn có một trường văn bản trong một ứng dụng, cho dù nó dựa trên trình duyệt hay máy tính để bàn và bạn đang chuyển thẳng giá trị vào quy trình và nếu bạn sử dụng thủ thuật trên thì chắc chắn điều này sẽ xảy ra.
Một ví dụ để ngăn chặn SQL Injection
Bây giờ chúng ta sẽ sửa đổi thủ tục trên để sử dụng biến ràng buộc thay vì nối giá trị tham số và theo cách này, không có thủ thuật SQL Injection nào có thể hoạt động.
CREATE OR REPLACE PROCEDURE PRC_GET_EMP_SAL_2 (p_empno VARCHAR2) IS --Declare a ref cursor and local variables-- TYPE C IS REF CURSOR; CUR_EMP C; L_ENAME VARCHAR2 (100); L_SAL NUMBER; L_STMT VARCHAR2 (4000); BEGIN --Open the ref cursor for a Dynamic SELECT statement-- L_STMT := 'SELECT ename, sal FROM emp WHERE empno = :p_bind_empno'; OPEN CUR_EMP FOR L_STMT USING p_EMPNO; LOOP --Fetch the result set and print the result set-- FETCH CUR_EMP INTO L_ENAME, L_SAL; EXIT WHEN CUR_EMP%NOTFOUND; DBMS_OUTPUT.PUT_LINE (L_ENAME || ' -- ' || L_SAL); END LOOP; CLOSE CUR_EMP; EXCEPTION WHEN OTHERS THEN DBMS_OUTPUT.PUT_LINE ('Can not fetch any records for: ' || p_empno); END; /
Kiểm tra quy trình trên một cách bình thường
SET SERVEROUTPUT ON; BEGIN prc_get_emp_sal_2 ('7566'); END; /
Đầu ra
JONES -- 27706.89 PL/SQL procedure successfully completed.
Kiểm tra quy trình trên bằng SQL Injection
SET SERVEROUTPUT ON; BEGIN prc_get_emp_sal_2 ('1'' OR ''1''= ''1'); END; /
Đầu ra Chèn SQL không thành công
Can not fetch any records for: 1' OR '1'= '1 PL/SQL procedure successfully completed.
Vì vậy, hãy ghi nhớ nó, nếu bạn đang tạo chương trình PL / SQL bằng SQL động, hãy sử dụng các phương thức liên kết.