SQL 주입은 매우 간단한 공격 방법이지만 오늘날에는 여전히 매우 일반적입니다. 그 이유는 그 이상입니다 : 멍청한 패치는 없습니다. 왜 그렇게 말합니까? Java를 예로 들어 보자.
데이터베이스에 이와 같은 테이블이 있다고 가정합니다.
테이블 사용자 (Id Varchar (20) 기본 키, 이름 varchar (20), Age Varchar (20));
그런 다음 JDBC를 사용하여 테이블을 작동합니다.
개인 문자열 getNameByUserId (String userId) {Connection Conn = getConn (); // 연결 문자열 sql = "id =" + userId 사용자에서 이름을 선택하십시오. PRESEDSTATEMEN PSTMT = CONN.PREPARESTATEMENT (SQL); resultSet rs = pstmt.executeUpdate (); ......}위의 코드는 종종 일부 개발자가 사용합니다. 전달 된 userID 매개 변수가 "3; 드롭 테이블 사용자;"인 경우, 실행 된 SQL 문은 다음과 같습니다.
id = 3 인 사용자 중에서 이름을 선택하십시오. 드롭 테이블 사용자;
데이터베이스를 컴파일하고 실행 한 후 사용자 테이블이 삭제됩니다. 간단한 SQL 주사 공격이 적용됩니다! 위의 코드는 프로그래밍 사양을 준수하지 않기 때문입니다.
사양에 따라 프로그램 할 때 SQL 주입이 존재하지 않습니다. 이것은 또한 SQL 주입을 피하는 첫 번째 방법입니다. 사전 컴파일 된 문서, 코드는 다음과 같습니다.
Connection Conn = getConn (); // 연결 문자열 sql = "id =?"; PRESEDSTATEMEN PSTMT = CONN.PREPARESTATEMENT (SQL); PSTMT.SETSTRING (1, userID); resultSet rs = pstmt.executeUpdate (); .... ....
위의 코드에 SQL 주입이 존재하지 않는 이유는 무엇입니까? 사전 컴파일 된 진술이 사용되기 때문에 사전 컴파일 된 문은 "id =???" 실행할 때 미리 명세서를 실행할 때 전달 된 매개 변수로만 바꾸면 되나요? 자리 표시 자. 사양을 준수하지 않는 첫 번째 경우, 프로그램은 SQL 문을 생성 한 다음 사용자가 전달한 컨텐츠로 컴파일합니다. 이것은 정확히 문제입니다.
사전 컴파일 된 진술을 사용하는 것 외에도 SQL 주입 공격을 피하는 두 번째 방법 : 저장 절차가 있습니다. 저장 프로 시저는 특정 기능을 완료하는 일련의 SQL 문입니다. 컴파일 후 데이터베이스에 저장됩니다. 저장 프로 시저를 호출하고 매개 변수를 제공하여 (저장 프로 시저에 매개 변수가있는 경우) SQL 주입 공격을 피할 수 있습니다.
연결 conn = getConn (); stmt = conn.preparecall ( "{call name_from_user (?,?)}"); stmt.setint (1,2); stmt.registeroutparameter (2, type.varchar); stmt.execute (); 문자열 이름 = stmt.getString (2);위 코드의 해당 저장 절차는 다음과 같습니다.
사용자 사용; delimiter // 프로 시저 생성 절차 생성 name_from_user (user_id int, out user_name varchar (20)) user id = user_id; 끝 // 구분자;
물론 사용자는 프론트 엔드에서 문자 검사를 수행 할 수도 있는데, 이는 SQL 주입을 피하는 방법이기도합니다. 예를 들어, 위의 UserID 매개 변수의 경우 세미콜론이 포함되어 있는지 확인할 때 사용자가 오류가 발생합니다.
그러나 가장 근본적인 이유로 인해 앱이 데이터베이스에 액세스 할 때 최소 권한을 사용하지 않기 때문에 SQL 주입 공격이 존재합니다. 나는 모든 사람이 루트 계정을 사용하여 데이터베이스에 액세스하고있는 것 같습니다.
그렇다면 Mybatis는 SQL 주입 공격을 어떻게 피합니까? 위의 테이블 사용자를 예로 사용하겠습니다.
Mapper 파일이 다음과 같이 가정합니다.
<select id = "getNameByUserId"resultType = "String"> id = #{userId} </select> 사용자에서 이름을 선택하십시오.해당 Java 파일은 다음과 같습니다.
public interface usermapper {String getNameByUserId (@param ( "userId") String userId); }입력 매개 변수가 String 유형의 userId임을 알 수 있습니다. userId = "34; 드롭 테이블 사용자;" 인쇄 된 진술은 다음과 같습니다.
id =?
어떤 userID를 입력하든 그의 SQL 문은 다음과 같습니다. 이는 기본 구현에서 사전 컴파일 된 진술을 사용하기 때문입니다. 데이터베이스 가이 명령문을 실행하면 사전 컴파일 된 명령문을 직접 사용한 다음 자리 표시자를 전달 된 userID로 대체합니까? 그냥 실행하러 가십시오. 자리 표시자를 먼저 교체하기 위해 존재하지 않습니까? 컴파일 프로세스가 수행되므로 SQL 주입을위한 생존의 여지가 없습니다.
그렇다면 mybatis는 어떻게 SQL의 사전 컴파일을 달성합니까? 실제로 프레임 워크는 ProadingStatement 클래스를 사용하고 있습니다. 준비된 클래스는 SQL 주입을 피할뿐만 아니라 사전 컴파일 되었기 때문입니다. 동일한 SQL 문이 n 번 실행되면 (n-1) 컴파일 시간을 절약하여 효율성을 향상시킵니다.
위의 진술을 변경하면 다음으로
<select id = "getNameByUserId"resultType = "String"> id = $ {userId} </select> 사용자에서 이름을 선택하십시오. userId="34;drop table user;" , 인쇄 된 진술은 다음과 같습니다.
id = 34; 드롭 테이블 사용자;
현재 Mybatis는 사전 컴파일 된 진술을 사용하지 않습니다. 먼저 문자열 스티칭을 수행 한 다음 컴파일을 수행합니다. 이 과정은 SQL 주입 과정입니다.
따라서 mybatis 매핑 명령문을 작성할 때 "#{xxx}"형식을 사용하십시오. "$ {xxx}"와 같은 매개 변수를 사용해야하는 경우 SQL 주입 공격을 방지하기 위해 수동으로 필터링을 잘 수행해야합니다.
요약
위의 것은 MyBatis에 의한 SQL 주입을 방지하는 방법에 대한 자세한 설명입니다. 나는 그것이 당신에게 도움이되기를 바랍니다. 궁금한 점이 있으면 메시지를 남겨 주시면 편집자가 제 시간에 답장을 드리겠습니다. Wulin.com 웹 사이트를 지원해 주셔서 대단히 감사합니다!