We continue to develop PVS-Studio as a SAST solution. One of the areas in which work is underway is improving OWASP coverage. And what is OWASP without taint analysis? So we thought so and decided to attach it to the C # analyzer. About what worked and what not, below.
. SQL SQL C#. taint .
taint ?
, taint , (taint source). "" . (taint sinks), : SQLI, XSS .. taint , , taint source taint sink.
:
- (taint sources);
- (taint sinks);
- ;
- .
, . ;)
:
var userName = Request.QueryString["userName"];
var rawCommand = "SELECT * FROM users WHERE name = '" + userName + "'";
var sqlCommand = new SqlCommand(rawCommand);
// Execution of the tainted command
"" SQL – , - . , . , , SQL-. JohnSmith? Sergey'; DROP TABLE users; --. .
Taint PVS-Studio:
++
PVS-Studio, taint , C C++ . taint V1010. , : , . , – system. , ( ). C++ Russia 2018 , .
. , CVE, - . , , - CVE-. . :)
C#
taint C# . , , C++ . " V1010 C# " , - . , , C# 2021 – OWASP ( – OWASP Top 10 2017, ASVS ). , .
, taint , SQL . , OWASP Top 10 2017 (A1:2017-Injection) OWASP ASVS – . .
Taint PVS-Studio C#: ?
data-flow . , . , , , .
, : data-flow, , false positives . , , .
taint .
(taint sources)
. , . , , .
:
- HttpRequest.QueryString;
- TextBox.Text;
- Console.ReadLine;
- ..
, taintedVariable .
void Example()
{
var taintedVariable = Console.ReadLine();
TaintSink(taintedVariable);
}
, . , public public :
public class Helper
{
public void ExecuteCommand(String commandToExecute)
{
TaintSink(commandToExecute);
}
}
ExecuteCommand commandToExecute . . , , API . – - . :)
, , , . - GitHub, , . , , .
, . , – .
, , , , , . — , .
PVS-Studio , , , . . , , , taint sink .
- , .
public class DBHelper
{
public void ProcessUserInfo(String userName)
{
....
var command = "SELECT * FROM Users WHERE userName = '" + userName + "'";
ExecuteCommand(command);
....
}
private void ExecuteCommand(String rawCommand)
{
using (SqlConnection connection = new SqlConnection(_connectionString))
{
....
using (var sqlCommand = new SqlCommand(rawCommand, connection))
{
using (var reader = sqlCommand.ExecuteReader())
....
}
}
}
}
ProcessUserInfo (public public ). userName SQL ( command). command ExecuteCommand. — rawCommand — SQL (sqlCommand), . , taint .
, — - . SQLILib.dll. ( SQLIApp.exe), ProcessUserInfo :
static void TestHelper(DBHelper helper)
{
var userName = Request.Form["userName"];
helper.ProcessUserInfo(userName);
}
, (Request.Form["userName"]), ProcessUserInfo. ProcessUserInfo — , .
, , — .
, , , . , API. , , .
, SQLIApp.exe SQL , ProcessUserInfo. , .
, — , taint . SQL .
. , //-V::5608:3 .pvsconfig . V5608 (SQLI) . .pvsconfig " " ( " (.pvsconfig)").
, , , //V_LEVEL_1::5608. " " " ".
(taint sinks)
. , taint . , , . , taint source taint sink — .
, SQL , SQLCommand FromSqlRaw.
:
var taintedStr = GetTaintedData();
var sqlCommand = new SqlCommand(taintedStr); // taint sink
....
, SqlCommand — , , , - : SqlCommand.ExecuteSomehow. , . , . SqlCommand — sink, .
SqlCommand.CommandText. :
void ProcessUserInfo()
{
using (SqlConnection connection = new SqlConnection(_connectionString))
{
....
String userName = Request.Form["userName"];
using (var command = new SqlCommand()
{
Connection = connection,
CommandText = "SELECT * FROM Users WHERE UserName = '" + userName + "'",
CommandType = System.Data.CommandType.Text
})
{
using (var reader = command.ExecuteReader())
....
}
}
}
SqlCommand, , CommandText.
, . :
- , - ;
- , ;
- , .
, , , - .
. , : SQL , - .. SQLI, , .
String userName = Request.Form["userName"];
using (var command = new SqlCommand()
{
Connection = connection,
CommandText = "SELECT * FROM Users WHERE UserName = @userName",
CommandType = System.Data.CommandType.Text
})
{
var userNameParam = new SqlParameter("@userName", userName);
command.Parameters.Add(userNameParam);
using (var reader = command.ExecuteReader())
....
}
taint SqlParameter. , . , userNameParam . userName , .
, taint source taint sink. , , . :) , taint sink. . — .
, , :
void Example()
{
var taintedVariable = Console.ReadLine();
TaintSink(taintedVariable);
}
Console.ReadLine() taintedVariable .
:
var taintedVariable = Console.ReadLine();
var taintedVariable2 = taintedVariable;
. , :
var shipCity = Console.ReadLine();
var resStr
= "select * from OrdersTable where ShipCity = '" + shipCity + "'";
, , . , .
:
var resStr = $"select * from UsersTable where Id = '{id}'";
— , , .
— . , . :)
— . :
var resStr = String.Join(separator, nonTaintedStr, taintedStr);
taintedStr String.Join, — resStr.
, , — , . — StringBuilder.
var sb = new StringBuilder();
sb.AppendLine(taintedStr);
var resStr = sb.ToString();
sb , AppendLine, taintedStr . , sb , . resStr ToString, .
, , — .
?
, , — . , data-flow C# , int, byte, short .. - , (- , ), . .
, taint , . , . false positive , , - , , . .
taint-based
. , .
- , sink' .
- — , sink'.
- sink, , taint .
- ...
- PROFIT!
, , , , .
taint : SQLI
, taint SQL .
, SQL , .. . , docs.microsoft.com. .
taint , . - (taint source). , , . , SQL (sink). , , , . .
. "SQLI C#", - :
private HttpRequest Request { get; set; }
void ProcessUserInfo()
{
using (SqlConnection connection = new SqlConnection(_connectionString))
{
....
String userName = Request.Form["userName"];
using (var command = new SqlCommand()
{
Connection = connection,
CommandText = "SELECT * FROM Users WHERE UserName = '" + userName + "'",
CommandType = System.Data.CommandType.Text
})
{
using (var reader = command.ExecuteReader())
....
}
}
}
, userName SQL - . , userName . , ' OR '1'='1, , .
. SQLI?
Request.Form ( Request HttpRequest). Form — NameValueCollection, . , ( ): Request.Form -> Request.Form["userName"]. userName , .
SqlCommand, . CommandText. CommandText — sink. . : "SELECT * FROM Users WHERE UserName = '" + userName + "'". , . , , , . , userName . . , , CommandText, , , .
Taint PVS-Studio 7.13. SQLI — V5608. .
, Twitter-. ;)
, : Sergey Vasiliev. OWASP, Vulnerabilities, and Taint Analysis in PVS-Studio for C#. Stir, but Don't Shake.