SQL Server에서 SQL 삽입으로 작은 따옴표를 벗어나는 위생을 어떻게 방지 할 수 있습니까?
이를 시작하기 위해 매개 변수화 된 쿼리가 최선의 선택이라는 것을 잘 알고 있지만 아래에 제시 한 전략을 취약하게 만드는 것이 무엇인지 묻고 있습니다. 사람들은 아래 솔루션이 작동하지 않는다고 주장하므로 작동하지 않는 이유에 대한 예를 찾고 있습니다.
동적 SQL이 SQL Server로 전송되기 전에 다음 이스케이프를 사용하여 코드에 내장 된 경우 어떤 종류의 주입이이를 방지 할 수 있습니까?
string userInput= "N'" + userInput.Replace("'", "''") + "'"
유사한 질문에 대한 답변이 여기 에 있지만 여기에 해당하는 답변이 없다고 생각합니다.
SQL Server에서는 작은 따옴표를 "\"로 이스케이프 할 수 없습니다.
나는 SQL Smuggling with Unicode ( 여기에 설명되어 있음 )가 생성되는 문자열이 작은 따옴표 앞의 N에 의해 Unicode로 표시된다는 사실에 의해 방해받을 것이라고 믿습니다 . 내가 아는 한 SQL Server가 자동으로 작은 따옴표로 변환하는 다른 문자 집합은 없습니다. 이스케이프 처리되지 않은 작은 따옴표 없이는 주입이 가능하다고 생각하지 않습니다.
나는 String Truncation 이 실행 가능한 벡터 라고 생각하지 않습니다 . microsoft에 따르면 의 최대 크기 nvarchar
가 2GB 이기 때문에 SQL Server는 확실히 자르기를 수행하지 않습니다 . 2GB 문자열은 대부분의 상황에서 실행 불가능하며 내에서는 불가능합니다.
Second Order Injection 이 가능할 수 있지만 다음과 같은 경우 가능합니다.
- 데이터베이스로 들어가는 모든 데이터는 위의 방법을 사용하여 삭제됩니다.
- 데이터베이스의 값은 동적 SQL에 추가되지 않습니다 (동적 SQL 문자열의 정적 부분에있는 테이블 값을 참조 할 수 있는데 왜 어쨌든 그렇게 하시겠습니까?).
이것이 매개 변수가있는 쿼리를 사용하는 것보다 낫거나 대안이라고 제안하는 것은 아니지만 내가 설명한 내용이 어떻게 취약한 지 알고 싶습니다. 어떤 아이디어?
이 탈출 기능이 실패하는 몇 가지 경우가 있습니다. 가장 분명한 것은 작은 따옴표가 사용되지 않는 경우입니다.
string table= "\"" + table.Replace("'", "''") + "\""
string var= "`" + var.Replace("'", "''") + "`"
string index= " " + index.Replace("'", "''") + " "
string query = "select * from `"+table+"` where name=\""+var+"\" or id="+index
이 경우 큰 따옴표, 백틱을 사용하여 "분리"할 수 있습니다. 마지막 경우에는 "탈출"할 것이 없으므로 1 union select password from users--
공격자가 원하는 SQL 페이로드를 작성 하거나 작성할 수 있습니다 .
이 이스케이프 기능이 실패하는 다음 조건은 문자열이 이스케이프 된 후 하위 문자열이 사용되는 경우입니다 ( 예 : 야생에서 이와 같은 취약점을 발견했습니다).
string userPassword= userPassword.Replace("'", "''")
string userName= userInput.Replace("'", "''")
userName = substr(userName,0,10)
string query = "select * from users where name='"+userName+"' and password='"+userPassword+"'";
이 경우의 사용자 이름 abcdefgji'
으로 설정됩니다 abcdefgji''
다음 이스케이프 함수 및 다시 설정 abcdefgji'
하위 문자열을 취함으로써. 이것은 암호 값을 sql 문으로 설정하여 악용 할 수 있습니다.이 경우에는 or 1=1--
sql로 해석되고 사용자 이름은 abcdefgji'' and password=
. 결과 쿼리는 다음과 같습니다.
select * from users where name='abcdefgji'' and password=' or 1=1--
이미 언급 한 T-SQL 및 기타 고급 SQL 주입 기술. SQL Server 애플리케이션의 고급 SQL 주입 은 훌륭한 문서이며 아직 읽지 않았다면 읽어야합니다.
마지막 문제는 유니 코드 공격입니다. 이 유형의 취약성은 이스케이프 기능이 멀티 바이트 인코딩을 인식하지 못하기 때문에 발생 하며 공격자가 이스케이프 문자를 "소비"하는 데 사용할 수 있습니다 . 문자열 앞에 "N"을 추가해도 도움이되지 않습니다. 이는 문자열의 뒷부분에있는 다중 바이트 문자 값에 영향을주지 않기 때문입니다. 그러나 이러한 유형의 공격은 데이터베이스가 GBK 유니 코드 문자열을 허용하도록 구성되어야하므로 매우 드물게 발생합니다 (MS-SQL이이를 수행 할 수 있는지 확실하지 않습니다).
2 차 코드 삽입은 여전히 가능하며,이 공격 패턴은 공격자가 제어하는 데이터 소스를 신뢰하여 생성됩니다. 이스케이프는 제어 문자를 문자 리터럴로 나타내는 데 사용됩니다. 개발자 잊어가에서 얻은 값을 탈출하는 경우 select
다음 다른 쿼리에서이 값을 사용하여 다음 BAM 공격자가 자신의 처분에 문자 리터럴 따옴표를해야합니다.
모든 것을 테스트하고 아무것도 믿지 마십시오.
몇 가지 추가 규정을 사용하면 위의 접근 방식이 SQL 주입에 취약하지 않습니다. 고려해야 할 주요 공격 벡터는 SQL Smuggling입니다. SQL Smuggling은 유사한 유니 코드 문자가 예기치 않은 방식으로 변환 될 때 발생합니다 (예 :`변경됨 '). 애플리케이션 스택이 SQL Smuggling에 취약 할 수있는 여러 위치가 있습니다.
프로그래밍 언어가 유니 코드 문자열을 적절하게 처리합니까? 언어가 유니 코드를 인식하지 못하는 경우 유니 코드 문자의 바이트를 작은 따옴표로 잘못 식별하고 이스케이프 할 수 있습니다.
클라이언트 데이터베이스 라이브러리 (예 : ODBC 등)가 유니 코드 문자열을 적절하게 처리합니까? .Net 프레임 워크의 System.Data.SqlClient는하지만 Windows 95 시대의 오래된 라이브러리는 어떻습니까? 타사 ODBC 라이브러리가 실제로 존재합니다. ODBC 드라이버가 쿼리 문자열에서 유니 코드를 지원하지 않으면 어떻게됩니까?
DB가 입력을 올바르게 처리합니까? 최신 버전의 SQL은 N ''을 사용한다고 가정 할 때 면역이 있지만 SQL 6.5는 어떻습니까? SQL 7.0? 나는 특정 취약점에 대해 알지 못하지만 1990 년대 개발자의 레이더에는 없었습니다.
버퍼 오버플로? 또 다른 문제는 인용 된 문자열이 원래 문자열보다 길다는 것입니다. 입력에 대한 2GB 제한이 도입 된 SQL Server 버전은 무엇입니까? 그 전에 한계가 무엇 이었습니까? 이전 버전의 SQL에서 쿼리가 제한을 초과하면 어떻게됩니까? 네트워크 라이브러리 관점에서 쿼리 길이에 제한이 있습니까? 아니면 프로그래밍 언어의 문자열 길이?
Replace () 함수에서 사용되는 비교에 영향을주는 언어 설정이 있습니까? .Net은 항상 Replace () 함수에 대해 이진 비교를 수행합니다. 항상 그럴까요? .NET의 향후 버전이 app.config 수준에서 해당 동작을 재정의하는 것을 지원하면 어떻게됩니까? 작은 따옴표를 삽입하기 위해 Replace () 대신 정규식을 사용하면 어떨까요? 컴퓨터의 로케일 설정이이 비교에 영향을 줍니까? 동작의 변화가 발생하면 SQL 인젝션에 취약하지 않을 수 있지만, DB에 도달하기 전에 작은 따옴표처럼 보이는 유니 코드 문자를 작은 따옴표로 변경하여 문자열을 실수로 편집했을 수 있습니다.
따라서 현재 (2005-2012) 버전의 SQL 서버에 대해 SqlClient 라이브러리가 내장 된 현재 버전의 .Net에서 C #의 System.String.Replace () 함수를 사용한다고 가정하면 접근 방식은 취약. 변화를 시작하면 약속을 할 수 없습니다. 매개 변수화 된 쿼리 접근 방식은 효율성, 성능 및 보안 (경우에 따라)에 대한 올바른 접근 방식입니다.
경고 위의 설명은이 기술을 보증하지 않습니다. 이것이 SQL 생성에 대한 잘못된 접근 방식 인 몇 가지 다른 이유가 있습니다. 그러나 세부 사항은이 질문의 범위를 벗어납니다.
이 기법을 새로운 개발에 사용하지 마십시오.
이 기법을 새로운 개발에 사용하지 마십시오.
이 기법을 새로운 개발에 사용하지 마십시오.
쿼리 매개 변수를 사용 하는 것이 따옴표를 이스케이프하는 것보다 더 좋고 쉽고 빠릅니다.
Re your comment, I see that you acknowledged parameterization, but it deserves emphasis. Why would you want to use escaping when you could parameterize?
In Advanced SQL Injection In SQL Server Applications, search for the word "replace" in the text, and from that point on read some examples where developers inadvertently allowed SQL injection attacks even after escaping user input.
There is an edge case where escaping quotes with \
results in a vulnerability, because the \
becomes half of a valid multi-byte character in some character sets. But this is not applicable to your case since \
isn't the escaping character.
As others have pointed out, you may also be adding dynamic content to your SQL for something other than a string literal or date literal. Table or column identifiers are delimited by "
in SQL, or [
]
in Microsoft/Sybase. SQL keywords of course don't have any delimiters. For these cases, I recommend whitelisting the values to interpolate.
Bottom line is that escaping is an effective defense, if you can ensure that you do it consistently. That's the risk: that one of the team of developers on your application could omit a step and do some string interpolation unsafely.
Of course, the same is true of other methods, like parameterization. They're only effective if you do them consistently. But I find it's easier to quicker to use parameters, than to figure out the right type of escaping. And developers are more likely to use a method that is convenient and doesn't slow them down.
SQL injection occur if user supplied inputs are interpreted as commands. Here command means anything that is not interpreted as a recognized data type literal.
Now if you’re using the user’s input only in data literals, specifically only in string literals, the user input would only be interpreted as something different than string data if it would be able to leave the string literal context. For character string or Unicode string literals, it’s the single quotation mark that encloses the literal data while embedded single quotation mark need to be represented with two single quotation marks.
So to leave a string literal context, one would need to supply a single single quotation mark (sic) as two single quotation marks are interpreted as string literal data and not as the string literal end delimiter.
So if you’re replacing any single quotation mark in the user supplied data by two single quotation marks, it will be impossible for the user to leave the string literal context.
SQL Injection can occur via unicode. If the web app has a URL like this:
http://mywebapp/widgets/?Code=ABC
which generates SQL like select * from widgets where Code = 'ABC'
but a hacker enters this:
http://mywebapp/widgets/?Code=ABC%CA%BC;drop table widgets--
the SQL will look like select * from widgets where Code = 'ABC’;drop table widgets--'
and SQL Server will run two SQL Statements. One to do the select and one to do the drop. Your code probably converts the url-encoded %CA%BC into unicode U02BC which is a "Modifier letter apostrophe". The Replace function in .Net will NOT treat that as a single quote. However Microsoft SQL Server treats it like a single quote. Here is an example that will probably allow SQL Injection:
string badValue = ((char)0x02BC).ToString();
badValue = badValue + ";delete from widgets--";
string sql = "SELECT * FROM WIDGETS WHERE ID=" + badValue.Replace("'","''");
TestTheSQL(sql);
There is probably no 100% safe way if you are doing string concatenation. What you can do is try to check data type for each parameter and if all parameters pass such validation then go ahead with execution. For example, if your parameter should be type int and you’re getting something that can’t be converted to int then just reject it.
This doesn’t work though if you’re accepting nvarchar parameters.
As others already pointed out. Safest way is to use parameterized query.
'Development Tip' 카테고리의 다른 글
사전에서 defaultdict를 구성하는 방법은 무엇입니까? (0) | 2020.11.18 |
---|---|
사용시기 (0) | 2020.11.18 |
git commit의 --date 매개 변수의 형식은 무엇입니까? (0) | 2020.11.18 |
이 C 프로그램은 두 가지 주요 기능으로 어떻게 컴파일되고 실행됩니까? (0) | 2020.11.18 |
무엇을 사용 : JPQL 또는 Criteria API? (0) | 2020.11.18 |