The dynamic value passed to the command execution should be validated.
Risk
If a malicious user controls either the FileName or Arguments, he might be able to execute unwanted commands or add unwanted argument. This behavior would not be possible if input parameter are validate against a white-list of characters.
Vulnerable Code
var p = new Process();
p.StartInfo.FileName = "exportLegacy.exe";
p.StartInfo.Arguments = " -user " + input + " -role user";
p.Start();
Solution
Regex rgx = new Regex(@"^[a-zA-Z0-9]+$");
if(rgx.IsMatch(input))
{
var p = new Process();
p.StartInfo.FileName = "exportLegacy.exe";
p.StartInfo.Arguments = " -user " + input + " -role user";
p.Start();
}
SQL injection flaws are introduced when software developers create dynamic database queries that include user supplied input.
Risk
Malicious user might get direct read and/or write access to the database. If the database is poorly configured the attacker might even get Remote Code Execution (RCE) on the machine running the database.
Vulnerable Code
var cmd = "SELECT * FROM Users WHERE username = '" + input + "' and role='user'";
ctx.Database.ExecuteSqlCommand(
cmd);
Solution
Use parametrized queries to mitigate SQL injection.
var cmd = "SELECT * FROM Users WHERE username = @username and role='user'";
ctx.Database.ExecuteSqlCommand(
cmd,
new SqlParameter("@username", input));
The XML parser is configured incorrectly. The operation could be vulnerable to XML eXternal Entity (XXE) processing.
Risk
Vulnerable Code
Prior to .NET 4.5.2
// DTD expansion is enabled by default
XmlReaderSettings settings = new XmlReaderSettings();
XmlReader reader = XmlReader.Create(inputXml, settings);
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.Load(pathToXmlFile);
Console.WriteLine(xmlDoc.InnerText);
Solution
Prior to .NET 4.5.2
var settings = new XmlReaderSettings();
// Prior to .NET 4.0
settings.ProhibitDtd = true; // default is false!// .NET 4.0 - .NET 4.5.2
settings.DtdProcessing = DtdProcessing.Prohibit; // default is DtdProcessing.Parse!
XmlReader reader = XmlReader.Create(inputXml, settings);
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.XmlResolver = null; // Setting this to NULL disables DTDs - Its NOT null by default.
xmlDoc.Load(pathToXmlFile);
Console.WriteLine(xmlDoc.InnerText);
.NET 4.5.2 and later
In .NET Framework versions 4.5.2 and up, XmlTextReader’s internal XmlResolver is set to null by default, making the XmlTextReader ignore DTDs by default. The XmlTextReader can become unsafe if if you create your own non-null XmlResolver with default or unsafe settings.
A path traversal attack (also known as directory traversal) aims to access files and directories that are stored outside the expected directory.By manipulating variables that reference files with “dot-dot-slash (../)” sequences and its variations or by using absolute file paths, it may be possible to access arbitrary files and directories stored on file system including application source code or configuration and critical system files.
Risk
With a malicious relative path, an attacker could reach a secret file.
A potential XSS was found. The endpoint returns a variable from the client input that has not been encoded. To protect against stored XSS attacks, make sure any dynamic content coming from user or data store cannot be used to inject JavaScript on a page. Most modern frameworks will escape dynamic content by default automatically (Razor for example) or by using special syntax (<%: content %>, <%= HttpUtility.HtmlEncode(content) %>).
Risk
XSS could be used to execute unwanted JavaScript in a client’s browser. XSS can be used to steal the cookie containing the user’s session ID. There is rarely a good reason to read or manipulate cookies in client-side JavaScript, so consider marking cookies as HTTP-only, meaning that cookies will be received, stored, and sent by the browser, but cannot be modified or read by JavaScript.
Certificate Validation has been disabled. The communication could be intercepted.
Risk
Disabling certificate validation is often used to connect easily to a host that is not signed by a root certificate authority. As a consequence, this is vulnerable to Man-in-the-middle attacks since the client will trust any certificate.
MD5 or SHA1 have known collision weaknesses and are no longer considered strong hashing algorithms.
Vulnerable Code
var hashProvider = new SHA1CryptoServiceProvider();
var hash = hashProvider.ComputeHash(str);
Solution
Use SHA256 or SHA512. Notice, that hashing algorithms are designed to be fast and shouldn’t be used directly for hashing passwords. Use adaptive algorithms for the purpose.
var hashProvider = SHA256Managed.Create();
var hash = hashProvider.ComputeHash(str);
DES and 3DES are not considered a strong cipher for modern applications. Currently, NIST recommends the usage of AES block ciphers instead.
Risk
Broken or deprecated ciphers have typically known weakness. A attacker might be able to brute force the secret key use for the encryption. The confidentiality and integrity of the information encrypted is at risk.
Vulnerable Code
DES DESalg = DES.Create();
// Create a string to encrypt. byte[] encrypted;
ICryptoTransform encryptor = DESalg.CreateEncryptor(key, zeroIV);
// Create the streams used for encryption. using (MemoryStream msEncrypt = new MemoryStream())
{
using (CryptoStream csEncrypt = new CryptoStream(msEncrypt,
encryptor,
CryptoStreamMode.Write))
{
using (StreamWriter swEncrypt = new StreamWriter(csEncrypt))
{
//Write all data to the stream.
swEncrypt.Write(Data);
}
encrypted = msEncrypt.ToArray();
return encrypted;
}
}
Solution
Use AES for symmetric encryption.
// Create a string to encrypt. byte[] encrypted;
var encryptor = new AesManaged();
encryptor.Key = key;
encryptor.GenerateIV();
var iv = encryptor.IV;
// Create the streams used for encryption. using (MemoryStream msEncrypt = new MemoryStream())
{
using (CryptoStream csEncrypt = new CryptoStream(msEncrypt,
encryptor.CreateEncryptor(),
CryptoStreamMode.Write))
{
using (StreamWriter swEncrypt = new StreamWriter(csEncrypt))
{
//Write all data to the stream.
swEncrypt.Write(Data);
}
encrypted = msEncrypt.ToArray();
return encrypted;
}
}
Notice that AES itself doesn’t protect from encrypted data tampering. For an example of authenticated encryption see the Solution in Weak Cipher Mode
The cipher text produced is susceptible to alteration by an adversary.
Risk
The cipher provides no way to detect that the data has been tampered with. If the cipher text can be controlled by an attacker, it could be altered without detection. The use of AES in CBC mode with a HMAC is recommended guaranteeing integrity and confidentiality.
Vulnerable Code
using (var aes = new AesManaged {
KeySize = KeyBitSize,
BlockSize = BlockBitSize,
Mode = CipherMode.OFB,
Padding = PaddingMode.PKCS7
})
{
using (var encrypter = aes.CreateEncryptor(cryptKey, newbyte[16]))
using (var cipherStream = new MemoryStream())
{
using (var cryptoStream = new CryptoStream(cipherStream, encrypter, CryptoStreamMode.Write))
using (var binaryWriter = new BinaryWriter(cryptoStream))
{
//Encrypt Data
binaryWriter.Write(secretMessage);
}
cipherText = cipherStream.ToArray();
}
}
//Missing HMAC suffix to assure integrity
Solution
Using bouncy castle:
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Crypto.Engines;
using Org.BouncyCastle.Crypto.Generators;
using Org.BouncyCastle.Crypto.Modes;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Security;
publicstaticreadonlyint BlockBitSize = 128;
publicstaticreadonlyint KeyBitSize = 256;
publicstaticbyte[] SimpleEncrypt(byte[] secretMessage, byte[] key)
{
//User Error Checksif (key == null || key.Length != KeyBitSize / 8)
thrownew ArgumentException(String.Format("Key needs to be {0} bit!", KeyBitSize), "key");
if (secretMessage == null || secretMessage.Length == 0)
thrownew ArgumentException("Secret Message Required!", "secretMessage");
//Using random nonce large enough not to repeatvar nonce = newbyte[NonceBitSize / 8];
Random.NextBytes(nonce, 0, nonce.Length);
var cipher = new GcmBlockCipher(new AesFastEngine());
var parameters = new AeadParameters(new KeyParameter(key), MacBitSize, nonce, newbyte[0]);
cipher.Init(true, parameters);
//Generate Cipher Text With Auth Tagvar cipherText = newbyte[cipher.GetOutputSize(secretMessage.Length)];
var len = cipher.ProcessBytes(secretMessage, 0, secretMessage.Length, cipherText, 0);
cipher.DoFinal(cipherText, len);
//Assemble Messageusing (var combinedStream = new MemoryStream())
{
using (var binaryWriter = new BinaryWriter(combinedStream))
{
//Prepend Nonce
binaryWriter.Write(nonce);
//Write Cipher Text
binaryWriter.Write(cipherText);
}
return combinedStream.ToArray();
}
}
Custom implementation of Encrypt and HMAC:
using System.IO;
using System.Security.Cryptography;
publicstaticbyte[] SimpleEncrypt(byte[] secretMessage, byte[] cryptKey, byte[] authKey, byte[] nonSecretPayload = null)
{
//User Error Checksif (cryptKey == null || cryptKey.Length != KeyBitSize / 8)
thrownew ArgumentException(String.Format("Key needs to be {0} bit!", KeyBitSize), "cryptKey");
if (authKey == null || authKey.Length != KeyBitSize / 8)
thrownew ArgumentException(String.Format("Key needs to be {0} bit!", KeyBitSize), "authKey");
if (secretMessage == null || secretMessage.Length < 1)
thrownew ArgumentException("Secret Message Required!", "secretMessage");
byte[] cipherText;
byte[] iv;
using (var aes = new AesManaged {
KeySize = KeyBitSize,
BlockSize = BlockBitSize,
Mode = CipherMode.CBC,
Padding = PaddingMode.PKCS7
})
{
//Use random IV
aes.GenerateIV();
iv = aes.IV;
using (var encrypter = aes.CreateEncryptor(cryptKey, iv))
using (var cipherStream = new MemoryStream())
{
using (var cryptoStream = new CryptoStream(cipherStream, encrypter, CryptoStreamMode.Write))
using (var binaryWriter = new BinaryWriter(cryptoStream))
{
//Encrypt Data
binaryWriter.Write(secretMessage);
}
cipherText = cipherStream.ToArray();
}
}
//Assemble encrypted message and add authenticationusing (var hmac = new HMACSHA256(authKey))
using (var encryptedStream = new MemoryStream())
{
using (var binaryWriter = new BinaryWriter(encryptedStream))
{
//Prepend IV
binaryWriter.Write(iv);
//Write Ciphertext
binaryWriter.Write(cipherText);
binaryWriter.Flush();
//Authenticate all datavar tag = hmac.ComputeHash(encryptedStream.ToArray());
//Postpend tag
binaryWriter.Write(tag);
}
return encryptedStream.ToArray();
}
}
It is recommended to specify the HttpOnly flag to new cookie.
Risk
Cookies that doesn’t have the flag set are available to JavaScript running on the same domain. When a user is the target of a “Cross-Site Scripting”, the attacker would benefit greatly from getting the session id.
Vulnerable Code
The httpOnlyCookies value is explicitly set to false or the default is left.
<httpCookieshttpOnlyCookies="false" [..] />
// default is leftvar cookie = new HttpCookie("test");
// or explicitly set to falsevar cookie = new HttpCookie("test");
cookie.HttpOnly = false;
Solution
<httpCookieshttpOnlyCookies="true" [..] />
var cookie = new HttpCookie("test");
cookie.Secure = true;
cookie.HttpOnly = true; //Add this flag
The viewStateEncryptionMode is not set to Always in configuration file.
Risk
Web Forms controls use hidden base64 encoded fields to store state information. If sensitive information is stored there it may be leaked to the client side.
Although it performs blacklisting (that is worse than whitelisting by definition) and you should not rely solely on it for XSS protection, it provides a first line of defense for your application. Do not disable the validation:
Although it performs blacklisting (that is worse than whitelisting by definition) and you should not rely solely on it for XSS protection, it provides a first line of defense for your application. Do not disable the validation: The default value is true. Or set it explicitly:
The password configuration to this API appears to be hardcoded.
Risk
If hard-coded passwords are used, it is almost certain that malicious users will gain access through the account in question.
Vulnerable Code
config.setPassword("NotSoSecr3tP@ssword");
Solution
It is recommended to externalize configuration such as password to avoid leakage of secret information. The source code or its binary form is more likely to be accessible by an attacker than a production configuration. To be managed safely, passwords and secret keys should be stored encrypted in separate configuration files. The certificate for decryption should be installed as non-exportable on the server machine.
PasswordValidator should have at least two requirements for better security (RequiredLength, RequireDigit, RequireLowercase, RequireUppercase and/or RequireNonLetterOrDigit).
Risk
Weak password can be guessed or brute-forced.
Vulnerable Code
PasswordValidator pwdv = new PasswordValidator
{
RequiredLength = 6,
};
SCS0012 - Controller method is potentially vulnerable to authorization bypass
Neither the annotation [Authorize], nor [AllowAnonymous] is present.
Risk
The endpoint is potentially accessible to not authorized users. If it contains sensitive information, like log files for example, it may lead to privilege escalation. The warning may be ignored/suppressed if the application is using other authorization checks. It is possible to customize the rule and register the additional attributes.
Vulnerable Code
publicclassAccountController : Controller
{
public ActionResult Login()
{
}
[Authorize]
public ActionResult Logout()
{
}
}
Solution
[Authorize]
publicclassAccountController : Controller
{
[AllowAnonymous]
public ActionResult Login()
{
}
public ActionResult Logout()
{
}
}
An attacker could send a link to the victim. By visiting the malicious link, a web page would trigger a POST request (because it is a blind attack - the attacker doesn’t see a response from triggered request and has no use from GET request and GET requests should not change a state on the server by definition) to the website. The victim would not be able to acknowledge that an action is made in the background, but his cookie would be automatically submitted if he is authenticated to the website. This attack does not require special interaction other than visiting a website.
Vulnerable Code
publicclassTestController
{
[HttpPost]
public ActionResult ControllerMethod(string input)
{
//Do an action in the context of the logged in user
}
}
Solution
In your view:
@Html.AntiForgeryToken()
In your controller:
publicclassTestController
{
[HttpPost]
[ValidateAntiForgeryToken] //Annotation addedpublic ActionResult ControllerMethod(string input)
{
//Do an action in the context of the logged in user
}
}
The enableEventValidation is disabled in configuration file.
Risk
This feature reduces the risk of unauthorized or malicious post-back requests and callbacks. It is strongly recommended that you do not disable event validation. When the EnableEventValidation property is set to true, ASP.NET validates that a control event originated from the user interface that was rendered by that control.
The dynamic value passed to the Redirect should be validated.
Risk
Your site may be used in phishing attacks. An attacker may craft a trustworthy looking link to your site redirecting a victim to a similar looking malicious site: https://www.yourdomain.com/loginpostback?redir=https://www.urdomain.com/login
Vulnerable Code
[HttpPost]
public ActionResult LogOn(LogOnModel model, string returnUrl)
{
if (ModelState.IsValid)
{
if (MembershipService.ValidateUser(model.UserName, model.Password))
{
FormsService.SignIn(model.UserName, model.RememberMe);
if (!String.IsNullOrEmpty(returnUrl))
{
return Redirect(returnUrl);
}
else
{
return RedirectToAction("Index", "Home");
}
}
else
{
ModelState.AddModelError("", "The user name or password provided is incorrect.");
}
}
// If we got this far, something failed, redisplay formreturn View(model);
}
Solution
[HttpPost]
public ActionResult LogOn(LogOnModel model, string returnUrl)
{
if (ModelState.IsValid)
{
if (MembershipService.ValidateUser(model.UserName, model.Password))
{
FormsService.SignIn(model.UserName, model.RememberMe);
if (Url.IsLocalUrl(returnUrl)) // Make sure the url is relative, not absolute path
{
return Redirect(returnUrl);
}
else
{
return RedirectToAction("Index", "Home");
}
}
else
{
ModelState.AddModelError("", "The user name or password provided is incorrect.");
}
}
// If we got this far, something failed, redisplay formreturn View(model);
}
Arbitrary code execution, full application compromise or denial of service. An attacker may pass specially crafted serialized .NET object of specific class that will execute malicious code during the construction of the object.
Vulnerable Code
privatevoidConvertData(string json)
{
var mySerializer = new JavaScriptSerializer(new SimpleTypeResolver());
Object mything = mySerializer.Deserialize(json, typeof(SomeDataClass)/* the type doesn't matter */);
}
Solution
There is no simple fix. Do not deserialize untrusted data: user input, cookies or data that crosses trust boundaries.
In case it is unavoidable: 1) If serialization is done on the server side, then crosses trust boundary, but is not modified and is returned back (like cookie for example) - use signed cryptography (HMAC for instance) to ensure it wasn’t tampered. 2) Do not get the type to deserialize into from untrusted source: the serialized stream itself or other untrusted parameter. BinaryFormatter for example reads type information from serialized stream itself and can’t be used with untrusted streams:
// DO NOT DO THIS!var thing = (MyType)new BinaryFormatter().Deserialize(untrustedStream);
JavaScriptSerializer for instance without a JavaScriptTypeResolver is safe because it doesn’t resolve types at all:
privatevoidConvertData(string json)
{
var mySerializer = new JavaScriptSerializer(/* no resolver here */);
Object mything = mySerializer.Deserialize(json, typeof(SomeDataClass));
}
Pass the expected type (may be hardcoded) to the deserialization library. Some libraries like Json.Net, DataContractJsonSerializer and FSPickler validate expected object graph before deserialization. However the check is not bulletproof if the expected type contains field or property of System.Object type somewhere nested in hierarchy.
// Json.net will inspect if the serialized data is the Expected typevar data = JsonConvert.DeserializeObject<Expected>(json, new
JsonSerializerSettings
{
// Type information is not used, only simple types like int, string, double, etc. will be resolved
TypeNameHandling = TypeNameHandling.None
});
// DO NOT DO THIS! The cast to MyType happens too late, when malicious code was already executedvar thing = (MyType)new BinaryFormatter().Deserialize(untrustedStream);
3) If the library supports implement a callback that verifies if the object and its properties are of expected type (don’t blacklist, use whitelist!):
classLimitedBinder : SerializationBinder
{
List<Type> allowedTypes = new List<Type>()
{
typeof(Exception),
typeof(List<Exception>),
};
publicoverride Type BindToType(string assemblyName, string typeName)
{
var type = Type.GetType(String.Format("{0}, {1}", typeName, assemblyName), true);
foreach(Type allowedType in allowedTypes)
{
if(type == allowedType)
return allowedType;
}
// Don’t return null for unexpected types –// this makes some serializers fall back to a default binder, allowing exploits.thrownew Exception("Unexpected serialized type");
}
}
var formatter = new BinaryFormatter() { Binder = new LimitedBinder () };
var data = (List<Exception>)formatter.Deserialize (fs);
Determining which types are safe is quite difficult, and this approach is not recommended unless necessary. There are many types that might allow non Remote Code Execution exploits if they are deserialized from untrusted data. Denial of service is especially common. As an example, the System.Collections.HashTable class is not safe to deserialize from an untrusted stream – the stream can specify the size of the internal “bucket” array and cause an out of memory condition.
4) Serialize simple Data Transfer Objects (DTO) only. Do not serialize/deserialize type information. For example, use only TypeNameHandling.None (the default) in Json.net:
classDataForStorage
{
publicstring Id;
publicint Count;
}
var data = JsonConvert.SerializeObject<DataForStorage>(json, new
JsonSerializerSettings
{
TypeNameHandling = TypeNameHandling.None
});
will produce the following JSON without type information that is perfectly fine to deserialize back:
var cmd = "SELECT * FROM Users WHERE username = '" + input + "' and role='user'";
ctx.Database.ExecuteSqlCommand(
cmd);
解決方案
使用參數化查詢來減輕 SQL 注入。
var cmd = "SELECT * FROM Users WHERE username = @username and role='user'";
ctx.Database.ExecuteSqlCommand(
cmd,
new SqlParameter("@username", input));
// DTD expansion is enabled by default
XmlReaderSettings settings = new XmlReaderSettings();
XmlReader reader = XmlReader.Create(inputXml, settings);
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.Load(pathToXmlFile);
Console.WriteLine(xmlDoc.InnerText);
解決方案
.NET 4.5.2 之前版本
var settings = new XmlReaderSettings();
// Prior to .NET 4.0
settings.ProhibitDtd = true; // default is false!// .NET 4.0 - .NET 4.5.2
settings.DtdProcessing = DtdProcessing.Prohibit; // default is DtdProcessing.Parse!
XmlReader reader = XmlReader.Create(inputXml, settings);
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.XmlResolver = null; // Setting this to NULL disables DTDs - Its NOT null by default.
xmlDoc.Load(pathToXmlFile);
Console.WriteLine(xmlDoc.InnerText);
DES DESalg = DES.Create();
// Create a string to encrypt. byte[] encrypted;
ICryptoTransform encryptor = DESalg.CreateEncryptor(key, zeroIV);
// Create the streams used for encryption. using (MemoryStream msEncrypt = new MemoryStream())
{
using (CryptoStream csEncrypt = new CryptoStream(msEncrypt,
encryptor,
CryptoStreamMode.Write))
{
using (StreamWriter swEncrypt = new StreamWriter(csEncrypt))
{
//Write all data to the stream.
swEncrypt.Write(Data);
}
encrypted = msEncrypt.ToArray();
return encrypted;
}
}
解決方案
使用 AES 進行對稱加密。
// Create a string to encrypt. byte[] encrypted;
var encryptor = new AesManaged();
encryptor.Key = key;
encryptor.GenerateIV();
var iv = encryptor.IV;
// Create the streams used for encryption. using (MemoryStream msEncrypt = new MemoryStream())
{
using (CryptoStream csEncrypt = new CryptoStream(msEncrypt,
encryptor.CreateEncryptor(),
CryptoStreamMode.Write))
{
using (StreamWriter swEncrypt = new StreamWriter(csEncrypt))
{
//Write all data to the stream.
swEncrypt.Write(Data);
}
encrypted = msEncrypt.ToArray();
return encrypted;
}
}
攻擊者可以向受害者發送連結。透過訪問惡意鏈接,網頁將觸發對網站的 POST 請求(因為這是一種盲目攻擊 - 攻擊者看不到觸發請求的回應,也不會使用 GET 請求,而且根據定義,GET 請求不應該改變伺服器上的狀態)。受害者無法確認後台執行的操作,但如果他透過網站驗證,他的 cookie 就會自動提交。除了訪問網站之外,此攻擊不需要任何特殊互動。
易受攻擊的程式碼
publicclassTestController
{
[HttpPost]
public ActionResult ControllerMethod(string input)
{
//Do an action in the context of the logged in user
}
}
解決方案
您認為:
@Html.AntiForgeryToken()
在您的控制器中:
publicclassTestController
{
[HttpPost]
[ValidateAntiForgeryToken] //Annotation addedpublic ActionResult ControllerMethod(string input)
{
//Do an action in the context of the logged in user
}
}
[HttpPost]
public ActionResult LogOn(LogOnModel model, string returnUrl)
{
if (ModelState.IsValid)
{
if (MembershipService.ValidateUser(model.UserName, model.Password))
{
FormsService.SignIn(model.UserName, model.RememberMe);
if (!String.IsNullOrEmpty(returnUrl))
{
return Redirect(returnUrl);
}
else
{
return RedirectToAction("Index", "Home");
}
}
else
{
ModelState.AddModelError("", "The user name or password provided is incorrect.");
}
}
// If we got this far, something failed, redisplay formreturn View(model);
}
解決方案
[HttpPost]
public ActionResult LogOn(LogOnModel model, string returnUrl)
{
if (ModelState.IsValid)
{
if (MembershipService.ValidateUser(model.UserName, model.Password))
{
FormsService.SignIn(model.UserName, model.RememberMe);
if (Url.IsLocalUrl(returnUrl)) // Make sure the url is relative, not absolute path
{
return Redirect(returnUrl);
}
else
{
return RedirectToAction("Index", "Home");
}
}
else
{
ModelState.AddModelError("", "The user name or password provided is incorrect.");
}
}
// If we got this far, something failed, redisplay formreturn View(model);
}
privatevoidConvertData(string json)
{
var mySerializer = new JavaScriptSerializer(new SimpleTypeResolver());
Object mything = mySerializer.Deserialize(json, typeof(SomeDataClass)/* the type doesn't matter */);
}
privatevoidConvertData(string json)
{
var mySerializer = new JavaScriptSerializer(/* no resolver here */);
Object mything = mySerializer.Deserialize(json, typeof(SomeDataClass));
}
// Json.net will inspect if the serialized data is the Expected typevar data = JsonConvert.DeserializeObject<Expected>(json, new
JsonSerializerSettings
{
// Type information is not used, only simple types like int, string, double, etc. will be resolved
TypeNameHandling = TypeNameHandling.None
});
// DO NOT DO THIS! The cast to MyType happens too late, when malicious code was already executedvar thing = (MyType)new BinaryFormatter().Deserialize(untrustedStream);
3)如果庫支援實現回調,則驗證物件及其屬性是否屬於預期類型(不要黑名單,使用白名單!):
classLimitedBinder : SerializationBinder
{
List<Type> allowedTypes = new List<Type>()
{
typeof(Exception),
typeof(List<Exception>),
};
publicoverride Type BindToType(string assemblyName, string typeName)
{
var type = Type.GetType(String.Format("{0}, {1}", typeName, assemblyName), true);
foreach(Type allowedType in allowedTypes)
{
if(type == allowedType)
return allowedType;
}
// Don’t return null for unexpected types –// this makes some serializers fall back to a default binder, allowing exploits.thrownew Exception("Unexpected serialized type");
}
}
var formatter = new BinaryFormatter() { Binder = new LimitedBinder () };
var data = (List<Exception>)formatter.Deserialize (fs);