0

私のasp.net mvcアプリケーションでは、ユーザーが登録すると、アプリを使用する前に検証用のリンクを含む電子メールをアカウントに送信します。以下のコード スニペットを参照してください。

        var emailActionLink = Url.Action("ValidateAccount", "Register",
            new { Token = registeredUserViewModel.Id, Username = registeredUserViewModel.Username },
            Request.Url.Scheme);

上記のスニペットは、クリックするものであり、ルート値を使用してアクションを呼び出します。

アカウント アクションの検証

    public ActionResult ValidateAccount(string token, string username)
    {
        try
        {
            if (!string.IsNullOrEmpty(token) && !string.IsNullOrEmpty(username))
            {
                var user = _userServiceClient.IsUserNameAvailable(username);
                if (!user.HasValue) throw new NullReferenceException("This account does not exist");



                var userContract = user.Value;
                userContract.EmailVerified = true;
                if (_userServiceClient.UpdateUser(userContract) == null) throw new Exception("Something has gone wrong");
                return View("ValidationCompleted");
            }
            else
            {
                ViewBag.RegisteredUser = null;
            }
        }
        catch (Exception exception)
        {
            throw;
        }

        return View();
    }

問題は、このメソッドがトークンを検証していないことです。誰かが uri の値を変更するとどうなるかtoken、これはまだ合格し、アカウントも同様です。これを改善するための正しいアプローチは何でしょうか。

この場合、トークンは Guid であるユーザーの ID ですが、エンコードされており、データベース内のユーザーの ID をこのエンコードされたトークンと比較する方法はありません。これはアクションリンクにエンコードされていると思います。

4

1 に答える 1

2

Id を使用するよりも、テーブルに Token フィールドを用意した方がよいでしょう (検証後にクリアできるように、null 可能)。URL セーフ トークンを生成し (特殊文字を使用しない 16 進文字列を使用します)、検証アクションでデータベース内のそのトークンを探します。

トークン ジェネレーターの例を次に示します。

public class TokenGenerator
{
    public static string GenerateToken(int size = 32)
    {
        var crypto = new RNGCryptoServiceProvider();
        byte[] rbytes = new byte[size / 2];
        crypto.GetNonZeroBytes(rbytes);

        return ToHexString(rbytes, true);
    }

    private static string ToHexString(byte[] bytes, bool useLowerCase = false)
    {
        var hex = string.Concat(bytes.Select(b => b.ToString(useLowerCase ? "x2" : "X2")));

        return hex;
    }
}

次に、適切なメソッドをサービス クラスに追加します。

public YourUserType GetUserForToken(string token, string userName)
{
    return YourDbContext.Users
        .SingleOrDfault(user => user.Token.Equals(token, StringComparison.OrdinalIgnoreCase) 
            && user.UserName.Equals(userName, StringComparison.OrdinalIgnoreCase));
}

明らかに、これはテーブル構造とデータ アクセス コードに関していくつかの仮定を行います。

于 2016-07-01T19:13:03.340 に答える