Updated REST to use an RNGCryptoServiceProvider for more secure random numbers involved in token generation.

Also removes some unnecessary limitations.
Closes #1388
This commit is contained in:
White 2017-01-31 11:25:59 +10:30
parent 94fb0e18b7
commit 26010c0acf

View file

@ -25,6 +25,7 @@ using TShockAPI;
using TShockAPI.DB; using TShockAPI.DB;
using Microsoft.Xna.Framework; using Microsoft.Xna.Framework;
using Terraria; using Terraria;
using System.Security.Cryptography;
namespace Rests namespace Rests
{ {
@ -41,6 +42,8 @@ namespace Rests
public Dictionary<string, TokenData> Tokens { get; protected set; } public Dictionary<string, TokenData> Tokens { get; protected set; }
public Dictionary<string, TokenData> AppTokens { get; protected set; } public Dictionary<string, TokenData> AppTokens { get; protected set; }
private RNGCryptoServiceProvider _rng = new RNGCryptoServiceProvider();
public SecureRest(IPAddress ip, int port) public SecureRest(IPAddress ip, int port)
: base(ip, port) : base(ip, port)
{ {
@ -112,7 +115,7 @@ namespace Rests
int tokens = 0; int tokens = 0;
if (tokenBucket.TryGetValue(context.RemoteEndPoint.Address.ToString(), out tokens)) if (tokenBucket.TryGetValue(context.RemoteEndPoint.Address.ToString(), out tokens))
{ {
if (tokens >= Math.Max(TShock.Config.RESTMaximumRequestsPerInterval, 5)) if (tokens >= TShock.Config.RESTMaximumRequestsPerInterval)
{ {
TShock.Log.ConsoleError("A REST login from {0} was blocked as it currently has {1} tokens", context.RemoteEndPoint.Address.ToString(), tokens); TShock.Log.ConsoleError("A REST login from {0} was blocked as it currently has {1} tokens", context.RemoteEndPoint.Address.ToString(), tokens);
tokenBucket[context.RemoteEndPoint.Address.ToString()] += 1; // Tokens over limit, increment by one and reject request tokenBucket[context.RemoteEndPoint.Address.ToString()] += 1; // Tokens over limit, increment by one and reject request
@ -121,8 +124,7 @@ namespace Rests
Error = "Username or password may be incorrect or this account may not have sufficient privileges." Error = "Username or password may be incorrect or this account may not have sufficient privileges."
}; };
} }
if (!TShock.Config.RESTLimitOnlyFailedLoginRequests) tokenBucket[context.RemoteEndPoint.Address.ToString()] += 1; // Tokens under limit, increment by one and process request
tokenBucket[context.RemoteEndPoint.Address.ToString()] += 1; // Tokens under limit, increment by one and process request
} }
else else
{ {
@ -150,13 +152,12 @@ namespace Rests
return new RestObject("403") return new RestObject("403")
{ Error = "Username or password may be incorrect or this account may not have sufficient privileges." }; { Error = "Username or password may be incorrect or this account may not have sufficient privileges." };
} }
string tokenHash; string tokenHash;
var rand = new Random();
var randbytes = new byte[32]; var randbytes = new byte[32];
do do
{ {
rand.NextBytes(randbytes); _rng.GetBytes(randbytes);
tokenHash = randbytes.Aggregate("", (s, b) => s + b.ToString("X2")); tokenHash = randbytes.Aggregate("", (s, b) => s + b.ToString("X2"));
} while (Tokens.ContainsKey(tokenHash)); } while (Tokens.ContainsKey(tokenHash));