Entity Framework Core - .Contains() - なぜパラメータ化の代わりにエスケープするのですか?

asp.net-core c# entity-framework-core linq sql

質問

Webアプリケーションでは、ViewModelのList<string>形式でユーザー入力を取得し、この情報を使用して次のコードでユーザーのIDを選択します。

var selectedUsersIds = Context.Users
.Where(user => SelectedUsers.Contains(user.Email))
.Select(user => user.Id)
.ToList();

SelectedUsersは文字列のリスト(ユーザーの電子メール)です。

今、アプリケーションログを見ているうちに、次のログエントリが見つかりました:

info: Microsoft.Data.Entity.Storage.Internal.RelationalCommandBuilderFactory[1]
  Executed DbCommand (0ms) [Parameters=[], CommandType='Text', CommandTimeout='30']
  SELECT [user].[Id]
  FROM [AspNetUsers] AS [user]
  WHERE [user].[Email] IN ('first@user.com', 'second@user.com')

そこで、次の作業は、残りのクライアントを使用しsome@user'--をフォームパラメータとして使用することでした。この結果が得られました。

info: Microsoft.Data.Entity.Storage.Internal.RelationalCommandBuilderFactory[1]
  Executed DbCommand (1ms) [Parameters=[], CommandType='Text', CommandTimeout='30']
  SELECT [user].[Id]
  FROM [AspNetUsers] AS [user]
  WHERE [user].[Email] IN ('some@user''--')

ここでは、 single ' double ''逃げましたdouble '' 。この動作は、「セキュリティ保証:LINQクエリでパラメータ化とエスケープを使用する」のドキュメントに記載されいるものと一貫しているようですが、クエリがパラメータ化またはエスケープされることを示しています。

しかし、クエリがパラメータ化されたときと値をエスケープするときは、どのように決定されるのでしょうか?いずれかの理由を選択する理由は何ですか?そして、エスケープは決して100%安全ではなかったと思いましたが、今は違うのですか?

受け入れられた回答

素晴らしい質問。 要素が定数に変換され、それがUPDATEまたはINSERTでない場合、それはエスケープされると答えています 。理由は次のとおりです。

SqlGenerator Souceを見ると、次のようなGenerateSqlというメソッドが表示されます。

internal static string GenerateSql(DbCommandTree tree, SqlVersion sqlVersion, out List<SqlParameter> parameters, out CommandType commandType, out HashSet<string> paramsToForceNonUnicode)
{
    SqlGenerator sqlGen;
    commandType = CommandType.Text;
    parameters = null;
    paramsToForceNonUnicode = null;

    switch (tree.CommandTreeKind)
    {
        case DbCommandTreeKind.Query:
            sqlGen = new SqlGenerator(sqlVersion);
            return sqlGen.GenerateSql((DbQueryCommandTree)tree, out paramsToForceNonUnicode);

        case DbCommandTreeKind.Insert:
            return DmlSqlGenerator.GenerateInsertSql((DbInsertCommandTree)tree, sqlVersion, out parameters);

        case DbCommandTreeKind.Delete:
            return DmlSqlGenerator.GenerateDeleteSql((DbDeleteCommandTree)tree, sqlVersion, out parameters);

        case DbCommandTreeKind.Update:
            return DmlSqlGenerator.GenerateUpdateSql((DbUpdateCommandTree)tree, sqlVersion, out parameters);

        case DbCommandTreeKind.Function:
            sqlGen = new SqlGenerator(sqlVersion);
            return GenerateFunctionSql((DbFunctionCommandTree)tree, out commandType);

        default:
            //We have covered all command tree kinds
            Debug.Assert(false, "Unknown command tree kind");
            parameters = null;
            return null;
    }
}

クエリであればわかるように、生成されたSQLをparamsなしで返します。他の種類の場合、 List<SqlParameter>ます。

定数を扱うかどうかについては、同じクラスの別の場所で見ることができます:

ここにコメントがあります:

//定数は、パラメータとしてではなく、生成されたTSQLの一部としてストアに送信されます

INSERTまたはUPDATEまたはDELETEの場合、パラメータを使用することがすでに決定されています。したがって、これはクエリ用です。あなたのList<string>は、ログから見たときに渡されたときに定数に変換されます。だから、それらの文字列に何が起こるかを知りたいだけです。

次に、そのタイプの大きなスイッチが発生します。

case PrimitiveTypeKind.String:
    bool isUnicode;

    if (!TypeHelpers.TryGetIsUnicode(e.ResultType, out isUnicode))
    {
        // If the unicode facet is not specified, if needed force non-unicode, otherwise default to unicode.
        isUnicode = !_forceNonUnicode;
    }
    result.Append(EscapeSingleQuote(e.Value as string, isUnicode));
    break;

シンプルなことは?

private static string EscapeSingleQuote(string s, bool isUnicode)
{
    return (isUnicode ? "N'" : "'") + s.Replace("'", "''") + "'";
}

あなたの他の質問について

いずれかの理由を選択する理由は何ですか?そして、エスケープは決して100%安全ではなかったと思いましたが、今は違うのですか?

私はセキュリティエキスパートではありませんが、「エスケープは100%安全ではありません」と同意しがちですが、誰かが100%安全な方法で制限することができます。面白いことは何も起こっていないことを100%確信していたときだけ、エスケープすることを選択しました。つまり、値がユーザーからまっすぐに届かない場合です。したがって、アクセス制限、リスク許容度、データの機密性、ユーザーロールなどの他の要素に基づいて、実装をさらにテストし、さらにセキュリティを強化する必要があるかどうかを判断することができます。



Related

ライセンスを受けた: CC-BY-SA with attribution
所属していない Stack Overflow
このKBは合法ですか? はい、理由を学ぶ
ライセンスを受けた: CC-BY-SA with attribution
所属していない Stack Overflow
このKBは合法ですか? はい、理由を学ぶ