2025年6月12日 星期四

A batch file for monitor the new disk drive and copy the file 偵測新磁碟並複製檔案

A batch file for monitor the new disk drive and copy the file.

monitor_drives.bat


@echo off

setlocal EnableDelayedExpansion


:: 設定 Default 檔案

REM set Default_FILE=TPM_default_test.txt

REM set RSC_Default_FILE=RSC_default_test.txt



:: 檢查是否提供了 Default_FILE , Default_Startup_FILE 參數

if "%1"=="" (

    echo Error: Please provide a Default_Startup_FILE ^(e.g., monitor_drivers.bat TPM_default_ChkVer.txt TPM_default_startup_ChkVer.nsh^)

    exit /b 0

)

if "%2"=="" (

    echo Error: Please provide a Default_Startup_FILE ^(e.g., monitor_drivers.bat TPM_default_ChkVer.txt TPM_default_startup_ChkVer.nsh^)

    exit /b 0

)


set Default_FILE=%1

set Default_Startup_FILE=%2


:: 設定輸出檔案路徑

set OUTPUT_FILE=detected_drives.txt


:: 清空或創建輸出檔案

echo. > %OUTPUT_FILE%


:: 儲存初始的磁碟機清單

set "PREV_DRIVES="

for /f "tokens=*" %%d in ('wmic logicaldisk where drivetype^=2 get deviceid ^| find ":"') do (

    set "PREV_DRIVES=!PREV_DRIVES! %%d"

)


:loop

:: 等待1秒

timeout /t 1 /nobreak >nul


:: 獲取當前磁碟機清單

set "CURRENT_DRIVES="

for /f "tokens=*" %%d in ('wmic logicaldisk where drivetype^=2 get deviceid ^| find ":"') do (

set "CURRENT_DRIVES=!CURRENT_DRIVES! %%d"

)


:: 檢查是否有新磁碟機

set "NEW_DRIVE="

for %%d in (%CURRENT_DRIVES%) do (

echo %PREV_DRIVES% | find /i "%%d" >nul || set "NEW_DRIVE=%%d"

)


:: 如果檢測到新磁碟機,將其寫入檔案

if defined NEW_DRIVE (

echo %NEW_DRIVE% > %OUTPUT_FILE%

REM echo %date% %time% - New drive detected: %NEW_DRIVE% >> %OUTPUT_FILE%

echo New drive detected: %NEW_DRIVE%

REM 讀取 detected_drives.txt 中最後一行的磁碟機代號,忽略空白行

REM set "DRIVE_LETTER="

REM for /f "tokens=1 delims= " %%a in ('echo "%NEW_DRIVE%" ^| findstr /v "^\s*$"') do (

REM set "DRIVE_LETTER=%%a"

REM )

REM echo DRIVE_LETTER: %NEW_DRIVE%

if defined NEW_DRIVE (

:: 等待3秒

timeout /t 3 /nobreak >nul

:: 直接比較 UTF-16 LE 檔案

fc /b %Default_FILE% %NEW_DRIVE%\default_test.txt > nul && (

echo "The file is same default_test.txt %Default_FILE%"

) || (

echo %NEW_DRIVE%\default_test.txt

echo "%Default_FILE%"

copy /Y %Default_FILE% %NEW_DRIVE%\default_test.txt

echo "%Default_Startup_FILE%"

copy /Y %Default_Startup_FILE% %NEW_DRIVE%\startup.nsh

)

)

)


:: 更新前一次的磁碟機清單

set "PREV_DRIVES=%CURRENT_DRIVES%"


goto loop

2025年6月9日 星期一

Arduino Nano program flash the hex, bin file

 這篇說明

1. 如何用 avrdude 燒錄 Arduino

2. 如何從 Arduino IDE 取得 hex , bin file


AVRDUDE is a utility to program AVR microcontrollers
https://github.com/avrdudes/avrdude/releases



✅ 前提條件(請確認)

  • 目標板子:Arduino Nano(ATmega328P)

  • 使用哪種方式上傳:

    1. 使用 USB 直接接 Nano(內建 CH340 或 FTDI)

    2. 使用 外部 ISP 燒錄器(如 USBasp、Arduino as ISP)


🔌 方式一:直接用 USB 線連接 Arduino Nano

Nano 自帶 bootloader,可以直接用 USB 上傳。

📌 指令範例(CH340 或 FTDI 晶片):

bash
avrdude -c arduino -p m328p -P COM3 -b 57600 -U flash:w:your_program.hex:i

📌 參數說明:

參數說明
-c arduino使用 Arduino bootloader protocol
-p m328pNano 的晶片 ATmega328P
-P COM3替換成你實際的 COM port
-b 57600舊版 bootloader(通常 Nano 這個 baudrate 就對)
-U flash:w:xxx.hex:i燒錄 hex 檔進 flash

💡 若你的 Nano 是新版(或 DIY 自燒 bootloader),也可能要改為 -b 115200


🧰 方式二:使用外部 ISP(如 USBasp 或 Arduino as ISP)

這會跳過 bootloader,直接燒錄程式進 flash。

【1】USBasp 方式:

bash
avrdude -c usbasp -p m328p -U flash:w:your_program.hex:i

【2】Arduino as ISP(使用 Arduino UNO 當 ISP):

bash
avrdude -c arduino -p m328p -P COM3 -b 19200 -U flash:w:your_program.hex:i

✅ 請確保 Arduino UNO 上有燒錄「ArduinoISP」範例程式


💡 從 Arduino IDE 取得 HEX 重點回顧

  • 點選:檔案 > 導出已編譯的二進位檔

  • 在專案資料夾會出現 .ino.hex.ino.with_bootloader.hex

    • 一般使用 .ino.hex(純程式)

    • .with_bootloader.hex 是要燒錄整個 bootloader 的


2025年5月8日 星期四

EFI/UEFI Shell commands list(指令集)

下列的指令集是依照不同的主機板廠商,提供不同的指令集:
?             - Displays the EFI Shell command list or verbose command help
alias         - Displays, creates, or deletes EFI Shell aliases
attrib        - Displays or changes the attributes of files or directories
cd            - Displays or changes the current directory
cls           - Clears standard output and optionally changes background color
comp          - Compares the contents of two files
connect       - Connects one or more EFI drivers to a device
cp            - Copies one or more files or directories to another location
date          - Displays or changes the current system date
dblk          - Displays one or more blocks from a block device
devices       - Displays the list of devices managed by EFI drivers
devtree       - Displays the EFI Driver Model compliant device tree
dh            - Displays EFI handle information
disconnect    - Disconnects one or more EFI drivers from a device
dmem          - Displays the contents of memory
dmpstore      - Displays all EFI NVRAM variables
drivers       - Displays the EFI driver list
drvcfg        - Invokes the Driver Configuration Protocol
drvdiag       - Invokes the Driver Diagnostics Protocol
echo          - Controls batch file command echoing or displays a message
edit          - Full screen editor for ASCII or UNICODE files
eficompress   - Compress a file
efidecompress - Decompress a file
err           - Displays or changes the error level
exit          - Exits the EFI Shell environment
for           - Executes commands for each item in a set of items
goto          - Forces batch file execution to jump to specified location
guid          - Displays all registered EFI GUIDs
help          - Displays the EFI Shell command list or verbose command help
hexedit       - Full screen hex editor
if            - Executes commands in specified conditions
ifconfig      - Modify the default IP address of UEFI network stack
ipconfig      - Displays or modifies the current IP configuration
load          - Loads and optionally connects one or more EFI drivers
loadpcirom    - Loads a PCI Option ROM
ls            - Displays a list of files and subdirectories in a directory
map           - Displays or defines mappings
mem           - Displays the contents of memory
memmap        - Displays the memory map
mkdir         - Creates one or more directories
mm            - Displays or modifies MEM/MMIO/IO/PCI/PCIE address space
mode          - Displays or changes the console output device mode
mount         - Mounts a file system on a block device
mv            - Moves one or more files or directories to another location
openinfo      - Displays the protocols and agents associated with a handle
pause         - Prints a message and waits for keyboard input
pci           - Displays PCI device list or PCI function configuration space
ping          - Ping a target machine with UEFI network stack
reconnect     - Reconnects one or more EFI drivers to a device
reset         - Resets the system
rm            - Deletes one or more files or directories
sermode       - Sets serial port attributes
set           - Displays or modifies EFI Shell environment variables
shift         - Shifts batch file input parameter positions
smbiosview    - Displays SMBIOS information
stall         - Stalls the processor for the specified number of microseconds
telnetmgmt    - Change terminal type
time          - Displays or changes the current system time
timezone      - Displays or sets time zone information
touch         - Updates filename timestamp with current system date and time
type          - Displays file contents
unload        - Unloads a EFI driver
ver           - Displays EFI Firmware version information
vol           - Displays or changes a file system volume label

Shell 2.0(UDK2010) 增加的指令
else      -Else identifies the portion of the code executed if the if was FALSE.
endif     -Ends the block of a script controlled by an 'if' statement.
endfor    -Ends a 'for' loop.
getmtc    -Gets the MTC from BootServices and displays it.
bcfg      -Manages the boot and driver options that are stored in NVRAM.
setsize   -Adjusts the size of a file.
setvar    -Changes the value of a UEFI variable.

UDK2014 增加的指令

prase      -Retrieves a value from a record output in a standard format. 

資料來源:https://samfreetime.blogspot.com/2011/09/efiuefi-shell-commands-list.html

2025年5月7日 星期三

Security Code Scan - static code analyzer for .NET Rules 安全程式碼掃描 - .NET 靜態程式碼分析器 規則

Rules

Injection

References

OWASP: Top 10 2013-A1-Injection

 SCS0001 - Command Injection 

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();
}

References

CWE-78: Improper Neutralization of Special Elements used in an OS Command (‘OS Command Injection’)
OWASP: Command Injection
OWASP: Top 10 2013-A1-Injection

 SCS0002 - SQL Injection 

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));

References

CWE-89: Improper Neutralization of Special Elements used in an SQL Command (‘SQL Injection’)
WASC-19: SQL Injection
OWASP: SQL Injection Prevention Cheat Sheet
OWASP: Query Parameterization Cheat Sheet
CAPEC-66: SQL Injection
Bobby Tables: A guide to preventing SQL injection

 SCS0003 - XPath Injection 

The dynamic value passed to the XPath query should be validated.

Risk

If the user input is not properly filtered, a malicious user could extend the XPath query.

Vulnerable Code

var doc = new XmlDocument {XmlResolver = null};
doc.Load("/config.xml");
var results = doc.SelectNodes("/Config/Devices/Device[id='" + input + "']");

Solution

Regex rgx = new Regex(@"^[a-zA-Z0-9]+$");
if(rgx.IsMatch(input)) //Additional validation
{
    XmlDocument doc = new XmlDocument {XmlResolver = null};
    doc.Load("/config.xml");
    var results = doc.SelectNodes("/Config/Devices/Device[id='" + input + "']");
}

References

CWE-643: Improper Neutralization of Data within XPath Expressions (‘XPath Injection’)
WASC-39: XPath Injection
OWASP: XPATH Injection
Black Hat Europe 2012: Hacking XPath 2.0

 SCS0007 - XML eXternal Entity Injection (XXE) 

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.

References

CWE-611: Improper Restriction of XML External Entity Reference (‘XXE’)
OWASP.org: XML External Entity (XXE) Prevention Cheat Sheet (.NET)
CERT: IDS10-J. Prevent XML external entity attacks
OWASP.org: XML External Entity (XXE) Processing
WS-Attacks.org: XML Entity Expansion
WS-Attacks.org: XML External Entity DOS
WS-Attacks.org: XML Entity Reference Attack
Identifying Xml eXternal Entity vulnerability (XXE)

 SCS0018 - Path Traversal 

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.

Vulnerable Code

[RedirectingAction]
public ActionResult Download(string fileName)
{
    byte[] fileBytes = System.IO.File.ReadAllBytes(Server.MapPath("~/ClientDocument/") + fileName);
    return File(fileBytes, System.Net.Mime.MediaTypeNames.Application.Octet, fileName);
}

The following request downloads a file of the attacker choice: http://www.address.com/Home/Download?fileName=../../somefile.txt

Solution

Do not try to strip invalid characters. Fail if any unexpected character is detected.

private static readonly char[] InvalidFilenameChars = Path.GetInvalidFileNameChars();

[RedirectingAction]
public ActionResult Download(string fileName)
{
    if (fileName.IndexOfAny(InvalidFilenameChars) >= 0)
        return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
        
    byte[] fileBytes = System.IO.File.ReadAllBytes(Server.MapPath("~/ClientDocument/") + fileName);
    return File(fileBytes, System.Net.Mime.MediaTypeNames.Application.Octet, fileName);
}

If the input is not supplied by user or a validation is in place the warning can be suppressed.

References

CWE-22: Improper Limitation of a Pathname to a Restricted Directory (‘Path Traversal’)
OWASP: Path Traversal
OS Command Injection, Path Traversal & Local File Inclusion Vulnerability - Notes

 SCS0029 - Cross-Site Scripting (XSS) 

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.

Vulnerable Code

public class TestController : Controller
{
    [HttpGet(""{myParam}"")]
    public string Get(string myParam)
    {
        return "value " + myParam;
    }
}

Solution

public class TestController : Controller
{
    [HttpGet(""{myParam}"")]
    public string Get(string myParam)
    {
        return "value " + HttpUtility.HtmlEncode(myParam);
    }
}

References

CWE-79: Improper Neutralization of Input During Web Page Generation (‘Cross-site Scripting’)
WASC-8: Cross Site Scripting
OWASP: XSS Prevention Cheat Sheet
OWASP: Top 10 2013-A3: Cross-Site Scripting (XSS)

 SCS0026 - LDAP Distinguished Name Injection 

The dynamic value passed to the LDAP query should be validated.

Risk

If the user input is not properly filtered, a malicious user could extend the LDAP query.

Vulnerable Code

var dir = new DirectoryEntry();
dir.Path = $"GC://DC={input},DC=com";

Solution

Use proper encoder (LdapFilterEncode or LdapDistinguishedNameEncode) from AntiXSS library:

var dir = new DirectoryEntry();
dir.Path = $"GC://DC={Encoder.LdapDistinguishedNameEncode(input)},DC=com";

References

CWE-90: Improper Neutralization of Special Elements used in an LDAP Query (‘LDAP Injection’)
WASC-29: LDAP Injection
OWASP: LDAP Injection
OWASP: LDAP Injection Prevention Cheat Sheet
MSDN Blog - Security Tools: LDAP Injection and mitigation

 SCS0031 - LDAP Filter Injection 

The dynamic value passed to the LDAP query should be validated.

Risk

If the user input is not properly filtered, a malicious user could extend the LDAP query.

Vulnerable Code

var searcher = new DirectorySearcher();
searcher.Filter = "(cn=" + input + ")";

Solution

Use proper encoder (LdapFilterEncode or LdapDistinguishedNameEncode) from AntiXSS library:

var searcher = new DirectorySearcher();
searcher.Filter = "(cn=" + Encoder.LdapFilterEncode(input) + ")";

References

CWE-90: Improper Neutralization of Special Elements used in an LDAP Query (‘LDAP Injection’)
WASC-29: LDAP Injection
OWASP: LDAP Injection
OWASP: LDAP Injection Prevention Cheat Sheet
MSDN Blog - Security Tools: LDAP Injection and mitigation

Cryptography

 SCS0004 - Certificate Validation Disabled 

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.

Vulnerable Code

ServicePointManager.ServerCertificateValidationCallback += (sender, cert, chain, sslPolicyErrors) => true;

Solution

  • Make sure the validation is disabled only in testing environment or
  • Use certificate pinning for development or
  • Use properly signed certificates for development
#if DEBUG
    ServicePointManager.ServerCertificateValidationCallback += (sender, cert, chain, sslPolicyErrors) => true;
#endif

References

CWE-295: Improper Certificate Validation
WASC-04: Insufficient Transport Layer Protection

 SCS0005 - Weak Random Number Generator 

The random numbers generated could be predicted.

Risk

The use of a predictable random value can lead to vulnerabilities when used in certain security critical contexts.

Vulnerable Code

var rnd = new Random();
byte[] buffer = new byte[16];
rnd.GetBytes(buffer);
return BitConverter.ToString(buffer);

Solution

using System.Security.Cryptography;
var rnd = RandomNumberGenerator.Create();

References

CWE-338: Use of Cryptographically Weak Pseudo-Random Number Generator (PRNG)
OWASP: Insecure Randomness

 SCS0006 - Weak hashing function 

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);

References

CWE-327: Use of a Broken or Risky Cryptographic Algorithm
MSDN: SHA256 Class documentation
Salted Password Hashing - Doing it Right

 SCS0010 - Weak cipher algorithm 

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

References

CWE-327: Use of a Broken or Risky Cryptographic Algorithm
NIST Withdraws Outdated Data Encryption Standard
StackOverflow: Authenticated encryption example

 SCS0013 - Potential usage of weak CipherMode 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, new byte[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;

public static readonly int BlockBitSize = 128;
public static readonly int KeyBitSize = 256;

public static byte[] SimpleEncrypt(byte[] secretMessage, byte[] key)
{
    //User Error Checks
    if (key == null || key.Length != KeyBitSize / 8)
        throw new ArgumentException(String.Format("Key needs to be {0} bit!", KeyBitSize), "key");

    if (secretMessage == null || secretMessage.Length == 0)
        throw new ArgumentException("Secret Message Required!", "secretMessage");

    //Using random nonce large enough not to repeat
    var nonce = new byte[NonceBitSize / 8];
    Random.NextBytes(nonce, 0, nonce.Length);

    var cipher = new GcmBlockCipher(new AesFastEngine());
    var parameters = new AeadParameters(new KeyParameter(key), MacBitSize, nonce, new byte[0]);
    cipher.Init(true, parameters);

    //Generate Cipher Text With Auth Tag
    var cipherText = new byte[cipher.GetOutputSize(secretMessage.Length)];
    var len = cipher.ProcessBytes(secretMessage, 0, secretMessage.Length, cipherText, 0);
    cipher.DoFinal(cipherText, len);

    //Assemble Message
    using (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;
public static byte[] SimpleEncrypt(byte[] secretMessage, byte[] cryptKey, byte[] authKey, byte[] nonSecretPayload = null)
{
    //User Error Checks
    if (cryptKey == null || cryptKey.Length != KeyBitSize / 8)
        throw new ArgumentException(String.Format("Key needs to be {0} bit!", KeyBitSize), "cryptKey");

    if (authKey == null || authKey.Length != KeyBitSize / 8)
        throw new ArgumentException(String.Format("Key needs to be {0} bit!", KeyBitSize), "authKey");

    if (secretMessage == null || secretMessage.Length < 1)
        throw new 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 authentication
    using (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 data
            var tag = hmac.ComputeHash(encryptedStream.ToArray());
            //Postpend tag
            binaryWriter.Write(tag);
        }
        return encryptedStream.ToArray();
    }
}

References

CWE-327: Use of a Broken or Risky Cryptographic Algorithm
Padding Oracles for the masses (by Matias Soler)
Wikipedia: Authenticated encryption
NIST: Authenticated Encryption Modes
CAPEC: Padding Oracle Crypto Attack
Wikipedia: ECB mode

Cookies

It is recommended to specify the Secure flag to new cookie.

Risk

The Secure flag is a directive to the browser to make sure that the cookie is not sent by unencrypted channel

Vulnerable Code

The requireSSL value is explicitly set to false or the default is left.

<httpCookies requireSSL="false" [..] />
// default is left
var cookie = new HttpCookie("test");
// or explicitly set to false
var cookie = new HttpCookie("test");
cookie.Secure = false;

Solution

<httpCookies requireSSL="true" [..] />
var cookie = new HttpCookie("test");
cookie.Secure = true; //Add this flag
cookie.HttpOnly = true;

References

CWE-614: Sensitive Cookie in HTTPS Session Without ‘Secure’ Attribute
OWASP: Secure Flag
Rapid7: Missing Secure Flag From SSL Cookie

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.

<httpCookies httpOnlyCookies="false" [..] />
// default is left
var cookie = new HttpCookie("test");
// or explicitly set to false
var cookie = new HttpCookie("test");
cookie.HttpOnly = false;

Solution

<httpCookies httpOnlyCookies="true" [..] />
var cookie = new HttpCookie("test");
cookie.Secure = true;
cookie.HttpOnly = true; //Add this flag

References

CWE-1004: Sensitive Cookie Without ‘HttpOnly’ Flag
Coding Horror blog: Protecting Your Cookies: HttpOnly
OWASP: HttpOnly
Rapid7: Missing HttpOnly Flag From Cookie

View State

 SCS0023 - View State Not Encrypted 

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.

Vulnerable Code

The default value is Auto:

<system.web>
   ...
   <pages [..] viewStateEncryptionMode="Auto" [..]/>
   ...
</system.web>

or

<system.web>
   ...
   <pages [..] viewStateEncryptionMode="Never" [..]/>
   ...
</system.web>

Solution

Explicitly set to Always and encrypt with with the .NET machine key:

<system.web>
   ...
   <pages [..] viewStateEncryptionMode="Always" [..]/>
   ...
</system.web>

References

CWE-554: ASP.NET Misconfiguration: Not Using Input Validation Framework
MSDN: pages Element (ASP.NET Settings Schema)
MSDN: ViewStateEncryptionMode Property
MSDN: machineKey Element (ASP.NET Settings Schema)

 SCS0024 - View State MAC Disabled 

The enableViewStateMac is disabled in configuration file. (This feature cannot be disabled starting .NET 4.5.1)

Risk

The view state could be altered by an attacker.

Vulnerable Code

<system.web>
   ...
   <pages [..] enableViewStateMac="false" [..]/>
   ...
</system.web>

Solution

The default value is secure - true. Or set it explicitly:

<system.web>
   ...
   <pages [..] enableViewStateMac="true" [..]/>
   ...
</system.web>

References

CWE-554: ASP.NET Misconfiguration: Not Using Input Validation Framework
MSDN: pages Element (ASP.NET Settings Schema)

Request Validation

 SCS0017 - Request Validation Disabled (Attribute) 

Request validation is disabled. Request validation allows the filtering of some XSS patterns submitted to the application.

Risk

XSS

Vulnerable Code

public class TestController
{
    [HttpPost]
    [ValidateInput(false)]
    public ActionResult ControllerMethod(string input) {
        return f(input);
    }
}

Solution

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:

public class TestController
{
    [HttpPost]
    public ActionResult ControllerMethod(string input) {
        return f(input);
    }
}

Always user proper encoder (Html, Url, etc.) before displaying or using user supplied data (even if it is loaded from database).

References

CWE-554: ASP.NET Misconfiguration: Not Using Input Validation Framework
MSDN: Request Validation in ASP.NET
OWASP: ASP.NET Request Validation
See XSS references.

 SCS0021 - Request Validation Disabled (Configuration File) 

The validateRequest which provides additional protection against XSS is disabled in configuration file.

Risk

XSS

Vulnerable Code

<system.web>
   ...
   <pages [..] validateRequest="false" [..]/>
   ...
</system.web>

Solution

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:

<system.web>
   ...
   <pages [..] validateRequest="true" [..]/>
   ...
</system.web>

References

CWE-554: ASP.NET Misconfiguration: Not Using Input Validation Framework
MSDN: pages Element (ASP.NET Settings Schema)
MSDN: Request Validation in ASP.NET
OWASP: ASP.NET Request Validation
See XSS references.

 SCS0030 - Request validation is enabled only for pages (Configuration File) 

The requestValidationMode which provides additional protection against XSS is enabled only for pages, not for all HTTP requests in configuration file.

Risk

XSS

Vulnerable Code

<system.web>
   ...
   <httpRuntime [..] requestValidationMode="2.0" [..]/>
   ...
</system.web>

Solution

<system.web>
   ...
   <httpRuntime [..] requestValidationMode="4.5" [..]/>
   ...
</system.web>

References

CWE-554: ASP.NET Misconfiguration: Not Using Input Validation Framework
MSDN: pages Element (ASP.NET Settings Schema)
MSDN: Request Validation in ASP.NET
OWASP: ASP.NET Request Validation
MSDN: RequestValidationMode Property
See XSS references.

Password Management

 SCS0015 - Hardcoded Password 

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.

Configuration file :

<configuration>
    <appSettings>
    <add key="api_password" value="b3e521073ca276dc2b7caf6247b6ddc72d5e2d2d" />
  </appSettings>
</configuration>

Code:

string apiPassword = ConfigurationManager.AppSettings["api_password"];
config.setPassword(apiPassword);

References

CWE-259: Use of Hard-coded Password

 SCS0034 - Password RequiredLength Not Set 

The RequiredLength property must be set with a minimum value of 8.

Risk

Weak password can be guessed or brute-forced.

Vulnerable Code

ASP.NET Identity default is 6.

PasswordValidator pwdv = new PasswordValidator();

Solution

See the solution for Password Complexity

References

CWE-521: Weak Password Requirements
MSDN: ASP.NET Identity PasswordValidator Class

 SCS0032 - Password RequiredLength Too Small 

The minimal length of a password is recommended to be set at least to 8.

Risk

Weak password can be guessed or brute-forced.

Vulnerable Code

PasswordValidator pwdv = new PasswordValidator
{
    RequiredLength = 6,
};

Solution

See the solution for Password Complexity

References

CWE-521: Weak Password Requirements
MSDN: ASP.NET Identity PasswordValidator Class

 SCS0033 - Password Complexity 

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,
};

Solution

PasswordValidator pwdv = new PasswordValidator
{
    RequiredLength = 8,
    RequireNonLetterOrDigit = true,
    RequireDigit = true,
    RequireLowercase = true,
    RequireUppercase = true,
};

References

CWE-521: Weak Password Requirements
MSDN: ASP.NET Identity PasswordValidator Class

Other

 SCS0011 - Unsafe XSLT setting used 

XSLT scripting should be enabled only if you require script support and you are working in a fully trusted environment.

Risk

This issue may lead to Remote Code Execution (RCE) if the XML source is untrusted.

Vulnerable Code

XslCompiledTransform transform = new XslCompiledTransform();
XsltSettings settings = new XsltSettings() {EnableScript = true};
transform.Load(xslPath, settings, null);
// Execute the transformation.
transform.Transform(reader, writer);

References

CWE-611: Improper Restriction of XML External Entity Reference
XSLT Server Side Injection Attacks
XML Attack for C# Remote Code Execution
XsltSettings.EnableScript Property

 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

public class AccountController : Controller
{
   public ActionResult Login()
   {
   }

   [Authorize]
   public ActionResult Logout()
   {
   }
}

Solution

[Authorize]
public class AccountController : Controller
{
    [AllowAnonymous]
    public ActionResult Login()
    {
    }

    public ActionResult Logout()
    {
    }
}

References

CWE-284: Improper Access Control
Access control vulnerabilities and privilege escalation
Simple authorization in ASP.NET Core

 SCS0016 - Cross-Site Request Forgery (CSRF) 

Anti-forgery token is missing.

Risk

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

public class TestController
{
    [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:

public class TestController
{
    [HttpPost]
    [ValidateAntiForgeryToken] //Annotation added
    public ActionResult ControllerMethod(string input)
    {
        //Do an action in the context of the logged in user
    }
}

References

CWE-352: Cross-Site Request Forgery (CSRF)
OWASP: Cross-Site Request Forgery
OWASP: CSRF Prevention Cheat Sheet

 SCS0019 - OutputCache Conflict 

Caching conflicts with authorization.

Risk

Having the annotation [OutputCache] will disable the annotation [Authorize] for the requests following the first one.

Vulnerable Code

[Authorize]
public class AdminController : Controller
{
    [OutputCache]
    public ActionResult Index()
    {
        return View();
    }
}

Solution

Remove the caching:

[Authorize]
public class AdminController : Controller
{
    public ActionResult Index()
    {
        return View();
    }
}

References

CWE-524: Use of Cache Containing Sensitive Information
Improving Performance with Output Caching

 SCS0022 - Event Validation Disabled 

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.

Vulnerable Code

<system.web>
   ...
   <pages [..] enableEventValidation="false" [..]/>
   ...
</system.web>

Solution

The default value is secure - true. Or set it explicitly:

<system.web>
   ...
   <pages [..] enableEventValidation="true" [..]/>
   ...
</system.web>

References

CWE-554: ASP.NET Misconfiguration: Not Using Input Validation Framework
MSDN: pages Element (ASP.NET Settings Schema)
MSDN: Page.EnableEventValidation Property

 SCS0027 - Open Redirect 

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 form
    return 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 form
    return View(model);
}

References

CWE-601: URL Redirection to Untrusted Site (‘Open Redirect’)
Microsoft: Preventing Open Redirection Attacks (C#)
OWASP: Unvalidated Redirects and Forwards Cheat Sheet
Hacksplaining: preventing malicious redirects

 SCS0028 - Insecure Deserialization 

Untrusted data passed for deserialization.

Risk

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

private void ConvertData(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:

private void ConvertData(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 type
var 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 executed
var 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!):

class LimitedBinder : SerializationBinder
{
    List<Type> allowedTypes = new List<Type>()
    {
        typeof(Exception),
        typeof(List<Exception>),
    };

    public override 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.
        throw new 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:

class DataForStorage
{
    public string Id;
    public int    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:

{
  "Id": null,
  "Count": 0
}

References

CWE-502: Deserialization of Untrusted Data
BlackHat USA 2017: Friday the 13th: JSON Attacks
BlueHat v17: Dangerous Contents - Securing .Net Deserialization
BlackHat USA 2012: Are you my type?
OWASP: Deserialization of untrusted data
Deserialization payload generator for a variety of .NET formatters

.NET Deserialization Passive Scanner 



規則

注射

參考

OWASP:2013 年十大 A1 注入漏洞

 SCS0001 - 指令注入 

傳遞給命令執行的動態值應該被驗證。

風險

如果惡意使用者控制了檔案名稱或參數,他可能能夠執行不需要的命令或新增不需要的參數。如果輸入參數根據字元白名單進行驗證,則這種行為不可能發生。

易受攻擊的程式碼

var p = new Process();
p.StartInfo.FileName = "exportLegacy.exe";
p.StartInfo.Arguments = " -user " + input + " -role user";
p.Start();

解決方案

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();
}

參考

CWE-78:作業系統指令中特殊元素的不當中和(「作業系統指令注入」)
OWASP:指令注入
OWASP:Top 10 2013-A1-注入

 SCS0002-SQL注入 

當軟體開發人員建立包含使用者提供的輸入的動態資料庫查詢時,就會引入 SQL 注入缺陷。

風險

惡意使用者可能會直接獲得資料庫的讀取和/或寫入權限。如果資料庫配置不當,攻擊者甚至可能在運行資料庫的機器上獲得遠端程式碼執行(RCE)。

易受攻擊的程式碼

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));

參考

CWE-89:SQL 指令中使用的特殊元素的不正確中和(「SQL 注入」)
WASC-19:SQL 注入
OWASP:SQL 注入預防備忘錄
OWASP:查詢參數化備忘單
CAPEC-66:SQL 注入
Bobby Tables:防止 SQL 注入的指南

 SCS0003-XPath注入 

傳遞給 XPath 查詢的動態值應該被驗證。

風險

如果使用者輸入沒有被正確過濾,惡意使用者可能會擴充 XPath 查詢。

易受攻擊的程式碼

var doc = new XmlDocument {XmlResolver = null};
doc.Load("/config.xml");
var results = doc.SelectNodes("/Config/Devices/Device[id='" + input + "']");

解決方案

Regex rgx = new Regex(@"^[a-zA-Z0-9]+$");
if(rgx.IsMatch(input)) //Additional validation
{
    XmlDocument doc = new XmlDocument {XmlResolver = null};
    doc.Load("/config.xml");
    var results = doc.SelectNodes("/Config/Devices/Device[id='" + input + "']");
}

參考

CWE-643:XPath 表達式中的資料中和不當(「XPath 注入」)
WASC-39:XPath 注入
OWASP:XPATH 注入
Black Hat Europe 2012:駭客攻擊 XPath 2.0

 SCS0007-XML 外部實體注入(XXE) 

XML 解析器配置不正確。此操作可能容易受到 XML 外部實體 (XXE) 處理的攻擊。

風險

易受攻擊的程式碼

.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);

解決方案

.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 及更高版本

在 .NET Framework 4.5.2 及更高版本中,XmlTextReader 的內部 XmlResolver 預設為 null,使得 XmlTextReader 預設忽略 DTD。如果您使用預設或不安全的設定來建立自己的非空 XmlResolver,則 XmlTextReader 可能會變得不安全。

參考

CWE-611:XML 外部實體參考(‘XXE’)的不當限制
OWASP.org:XML 外部實體(XXE)預防備忘單(.NET)
CERT:IDS10-J。防止 XML 外部實體攻擊
OWASP.org:XML 外部實體 (XXE) 處理
WS-Attacks.org:XML 實體擴展
WS-Attacks.org:XML 外部實體 DOS
WS-Attacks.org:XML 實體引用攻擊
識別 XML 外部實體漏洞 (XXE)

 SCS0018 - 路徑遍歷 

路徑遍歷攻擊(也稱為目錄遍歷)旨在存取儲存在預期目錄之外的檔案和目錄。透過操縱引用帶有「點-點-斜線 (../)」序列及其變體的檔案的變數或使用絕對檔案路徑,可以存取儲存在檔案系統上的任意檔案和目錄,包括應用程式原始程式碼或設定和關鍵系統檔案。

風險

利用惡意相對路徑,攻擊者可以取得秘密檔案。

易受攻擊的程式碼

[RedirectingAction]
public ActionResult Download(string fileName)
{
    byte[] fileBytes = System.IO.File.ReadAllBytes(Server.MapPath("~/ClientDocument/") + fileName);
    return File(fileBytes, System.Net.Mime.MediaTypeNames.Application.Octet, fileName);
}

以下請求下載攻擊者選擇的檔案: http://www.address.com/Home/Download?fileName=../../somefile.txt

解決方案

不要嘗試刪除無效字元。如果偵測到任何意外字符,則失敗。

private static readonly char[] InvalidFilenameChars = Path.GetInvalidFileNameChars();

[RedirectingAction]
public ActionResult Download(string fileName)
{
    if (fileName.IndexOfAny(InvalidFilenameChars) >= 0)
        return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
        
    byte[] fileBytes = System.IO.File.ReadAllBytes(Server.MapPath("~/ClientDocument/") + fileName);
    return File(fileBytes, System.Net.Mime.MediaTypeNames.Application.Octet, fileName);
}

如果使用者未提供輸入或已進行驗證,則可以抑制警告。

參考

CWE-22:將路徑名稱不正確地限製到受限目錄(「路徑遍歷」)
OWASP:路徑遍歷
作業系統命令注入、路徑遍歷和本機檔案包含漏洞 - 註釋

 SCS0029 - 跨站腳本 (XSS) 

發現了潛在的 XSS。端點傳回來自客戶端輸入的尚未編碼的變數。為了防止儲存型 XSS 攻擊,請確保來自使用者或資料儲存的任何動態內容不能用於在頁面上註入 JavaScript。大多數現代框架將預設自動轉義動態內容(例如 Razor)或使用特殊語法(<%: content %><%= HttpUtility.HtmlEncode(content) %>)。

風險

XSS 可用於在客戶端的瀏覽器中執行不需要的 JavaScript。 XSS 可用於竊取包含使用者會話 ID 的 cookie。很少有充分的理由在客戶端 JavaScript 中讀取或操作 cookie,因此請考慮將 cookie 標記為HTTP-only,這意味著 cookie 將由瀏覽器接收、儲存和發送,但不能由 JavaScript 修改或讀取。

易受攻擊的程式碼

public class TestController : Controller
{
    [HttpGet(""{myParam}"")]
    public string Get(string myParam)
    {
        return "value " + myParam;
    }
}

解決方案

public class TestController : Controller
{
    [HttpGet(""{myParam}"")]
    public string Get(string myParam)
    {
        return "value " + HttpUtility.HtmlEncode(myParam);
    }
}

參考

CWE-79:網頁產生過程中輸入的不當中和(「跨站點腳本」)
WASC-8:跨站點腳本
OWASP:XSS 預防備忘單
OWASP:Top 10 2013-A3:跨站點腳本(XSS)

 SCS0026 - LDAP 可分辨名稱注入 

應該驗證傳遞給 LDAP 查詢的動態值。

風險

如果使用者輸入沒有被正確過濾,惡意使用者可能會擴展 LDAP 查詢。

易受攻擊的程式碼

var dir = new DirectoryEntry();
dir.Path = $"GC://DC={input},DC=com";

解決方案

使用AntiXSS 庫中的適當編碼器(LdapFilterEncodeLdapDistinguishedNameEncode

var dir = new DirectoryEntry();
dir.Path = $"GC://DC={Encoder.LdapDistinguishedNameEncode(input)},DC=com";

參考

CWE-90:LDAP 查詢中使用的特殊元素的中和不當(「LDAP 注入」)
WASC-29:LDAP 注入
OWASP:LDAP 注入
OWASP:LDAP 注入預防備忘單
MSDN 部落格 - 安全工具:LDAP 注入和緩解

 SCS0031 - LDAP 過濾器注入 

應該驗證傳遞給 LDAP 查詢的動態值。

風險

如果使用者輸入沒有被正確過濾,惡意使用者可能會擴展 LDAP 查詢。

易受攻擊的程式碼

var searcher = new DirectorySearcher();
searcher.Filter = "(cn=" + input + ")";

解決方案

使用AntiXSS 庫中的適當編碼器(LdapFilterEncodeLdapDistinguishedNameEncode

var searcher = new DirectorySearcher();
searcher.Filter = "(cn=" + Encoder.LdapFilterEncode(input) + ")";

參考

CWE-90:LDAP 查詢中使用的特殊元素的中和不當(「LDAP 注入」)
WASC-29:LDAP 注入
OWASP:LDAP 注入
OWASP:LDAP 注入預防備忘單
MSDN 部落格 - 安全工具:LDAP 注入和緩解

密碼學

 SCS0004 - 憑證驗證已停用 

證書驗證已被停用。通訊可能會被截取。

風險

停用憑證驗證通常用於輕鬆連接到未經根憑證授權單位簽署的主機。因此,由於客戶端會信任任何證書,因此很容易受到中間人攻擊。

易受攻擊的程式碼

ServicePointManager.ServerCertificateValidationCallback += (sender, cert, chain, sslPolicyErrors) => true;

解決方案

  • 確保僅在測試環境中停用驗證,或
  • 使用證書固定進行開發或
  • 使用正確簽署的憑證進行開發
#if DEBUG
    ServicePointManager.ServerCertificateValidationCallback += (sender, cert, chain, sslPolicyErrors) => true;
#endif

參考

CWE-295:憑證驗證不當
WASC-04:傳輸層保護不足

 SCS0005 - 弱隨機數產生器 

產生的隨機數是可以預測的。

風險

在某些安全關鍵環境中使用可預測的隨機值可能會導致漏洞。

易受攻擊的程式碼

var rnd = new Random();
byte[] buffer = new byte[16];
rnd.GetBytes(buffer);
return BitConverter.ToString(buffer);

解決方案

using System.Security.Cryptography;
var rnd = RandomNumberGenerator.Create();

參考

CWE-338:使用加密弱偽隨機數產生器(PRNG)
OWASP:不安全的隨機性

 SCS0006 - 弱雜湊函數 

MD5 或 SHA1 具有已知的碰撞弱點,不再被視為強雜湊演算法。

易受攻擊的程式碼

var hashProvider = new SHA1CryptoServiceProvider();
var hash = hashProvider.ComputeHash(str);

解決方案

使用 SHA256 或 SHA512。請注意,雜湊演算法設計為快速的,不應直接用於雜湊密碼。使用自適應演算法來實現此目的。

var hashProvider = SHA256Managed.Create();
var hash = hashProvider.ComputeHash(str);

參考

CWE-327:使用損壞或有風險的加密演算法
MSDN:SHA256 類文件
加鹽密碼哈希 - 正確做法

 SCS0010 - 弱密碼演算法 

對於現代應用程式來說,DES 和 3DES 並不被視為強密碼。目前,NIST 建議使用 AES 分組密碼。

風險

被破解或棄用的密碼通常具有已知的弱點。攻擊者可能能夠強行取得用於加密的金鑰。加密資訊的機密性和完整性受到威脅。

易受攻擊的程式碼

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;
    }
}

請注意,AES 本身並不能防止加密資料被竄改。有關認證加密的範例,請參閱弱密碼模式下的解決方案

參考

CWE-327:使用損壞或有風險的加密演算法
NIST 撤回過時的資料加密標準
StackOverflow:經過身份驗證的加密範例

 SCS0013 - 可能使用弱 CipherMode 模式 

產生的密文很容易被對手更改。

風險

該密碼無法偵測資料是否被竄改。如果攻擊者可以控制密文,那麼就可以在不被發現的情況下進行更改。建議使用 CBC 模式的 AES 和 HMAC 來保證完整性和機密性。

易受攻擊的程式碼

using (var aes = new AesManaged {
    KeySize = KeyBitSize,
    BlockSize = BlockBitSize,
    Mode = CipherMode.OFB,
    Padding = PaddingMode.PKCS7
})
{
    using (var encrypter = aes.CreateEncryptor(cryptKey, new byte[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

解決方案

使用充氣城堡:

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;

public static readonly int BlockBitSize = 128;
public static readonly int KeyBitSize = 256;

public static byte[] SimpleEncrypt(byte[] secretMessage, byte[] key)
{
    //User Error Checks
    if (key == null || key.Length != KeyBitSize / 8)
        throw new ArgumentException(String.Format("Key needs to be {0} bit!", KeyBitSize), "key");

    if (secretMessage == null || secretMessage.Length == 0)
        throw new ArgumentException("Secret Message Required!", "secretMessage");

    //Using random nonce large enough not to repeat
    var nonce = new byte[NonceBitSize / 8];
    Random.NextBytes(nonce, 0, nonce.Length);

    var cipher = new GcmBlockCipher(new AesFastEngine());
    var parameters = new AeadParameters(new KeyParameter(key), MacBitSize, nonce, new byte[0]);
    cipher.Init(true, parameters);

    //Generate Cipher Text With Auth Tag
    var cipherText = new byte[cipher.GetOutputSize(secretMessage.Length)];
    var len = cipher.ProcessBytes(secretMessage, 0, secretMessage.Length, cipherText, 0);
    cipher.DoFinal(cipherText, len);

    //Assemble Message
    using (var combinedStream = new MemoryStream())
    {
        using (var binaryWriter = new BinaryWriter(combinedStream))
        {
            //Prepend Nonce
            binaryWriter.Write(nonce);
            //Write Cipher Text
            binaryWriter.Write(cipherText);
        }
        return combinedStream.ToArray();
    }
}

加密和 HMAC 的自訂實作:

using System.IO;
using System.Security.Cryptography;
public static byte[] SimpleEncrypt(byte[] secretMessage, byte[] cryptKey, byte[] authKey, byte[] nonSecretPayload = null)
{
    //User Error Checks
    if (cryptKey == null || cryptKey.Length != KeyBitSize / 8)
        throw new ArgumentException(String.Format("Key needs to be {0} bit!", KeyBitSize), "cryptKey");

    if (authKey == null || authKey.Length != KeyBitSize / 8)
        throw new ArgumentException(String.Format("Key needs to be {0} bit!", KeyBitSize), "authKey");

    if (secretMessage == null || secretMessage.Length < 1)
        throw new 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 authentication
    using (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 data
            var tag = hmac.ComputeHash(encryptedStream.ToArray());
            //Postpend tag
            binaryWriter.Write(tag);
        }
        return encryptedStream.ToArray();
    }
}

參考

CWE-327:使用破損或有風險的加密演算法
填充 Oracles 供大眾使用(作者:Matias Soler)
維基百科:經過身份驗證的加密
NIST:經過身份驗證的加密模式
CAPEC:填充 Oracle 加密攻擊
維基百科:ECB 模式

餅乾

建議為新的 cookie 指定安全標誌。

風險

安全標誌是向瀏覽器發出的指令,以確保 cookie 不會透過未加密的通道傳送

易受攻擊的程式碼

requireSSL值明確設定為false或保留預設值。

<httpCookies requireSSL="false" [..] />
// default is left
var cookie = new HttpCookie("test");
// or explicitly set to false
var cookie = new HttpCookie("test");
cookie.Secure = false;

解決方案

<httpCookies requireSSL="true" [..] />
var cookie = new HttpCookie("test");
cookie.Secure = true; //Add this flag
cookie.HttpOnly = true;

參考

CWE-614:HTTPS 會話中的敏感 Cookie 不具備「安全性」屬性
OWASP:安全標誌
Rapid7:SSL Cookie 中缺少安全標誌

建議為新的 cookie 指定 HttpOnly 標誌。

風險

未設定標誌的 Cookie 可供在同一網域上執行的 JavaScript 使用。當使用者成為「跨站點腳本」的目標時,攻擊者可以透過獲取會話 ID 獲得巨大利益。

易受攻擊的程式碼

httpOnlyCookies值明確設定為false或保留預設值。

<httpCookies httpOnlyCookies="false" [..] />
// default is left
var cookie = new HttpCookie("test");
// or explicitly set to false
var cookie = new HttpCookie("test");
cookie.HttpOnly = false;

解決方案

<httpCookies httpOnlyCookies="true" [..] />
var cookie = new HttpCookie("test");
cookie.Secure = true;
cookie.HttpOnly = true; //Add this flag

參考

CWE-1004:沒有「HttpOnly」標誌的敏感 Cookie
Coding Horror 部落格:保護您的 Cookie:HttpOnly
OWASP:HttpOnly
Rapid7:Cookie 中缺少 HttpOnly 標誌

視圖狀態

 SCS0023 - 視圖狀態未加密 

設定檔中viewStateEncryptionMode未設定為Always

風險

Web 窗體控制項使用隱藏的 base64 編碼欄位來儲存狀態資訊。如果敏感資訊儲存在那裡,則可能會洩漏給客戶端。

易受攻擊的程式碼

預設值為Auto

<system.web>
   ...
   <pages [..] viewStateEncryptionMode="Auto" [..]/>
   ...
</system.web>

或者

<system.web>
   ...
   <pages [..] viewStateEncryptionMode="Never" [..]/>
   ...
</system.web>

解決方案

明確設定為Always並使用 .NET機器密鑰加密:

<system.web>
   ...
   <pages [..] viewStateEncryptionMode="Always" [..]/>
   ...
</system.web>

參考

CWE-554:ASP.NET 設定錯誤:未使用輸入驗證框架
MSDN:pages 元素(ASP.NET 設定架構)
MSDN:ViewStateEncryptionMode 屬性
MSDN:machineKey 元素(ASP.NET 設定架構)

 SCS0024 - 檢視狀態 MAC 已停用 

在設定檔中被enableViewStateMac停用。 (從 .NET 4.5.1 開始無法停用此功能)

風險

視圖狀態可能會被攻擊者改變。

易受攻擊的程式碼

<system.web>
   ...
   <pages [..] enableViewStateMac="false" [..]/>
   ...
</system.web>

解決方案

預設值為 secure- true。或明確設定:

<system.web>
   ...
   <pages [..] enableViewStateMac="true" [..]/>
   ...
</system.web>

參考

CWE-554:ASP.NET 設定錯誤:未使用輸入驗證框架
MSDN:pages 元素(ASP.NET 設定架構)

請求驗證

 SCS0017 - 請求驗證已停用(屬性) 

請求驗證已停用。請求驗證允許過濾提交給應用程式的一些XSS模式。

風險

跨站腳本

易受攻擊的程式碼

public class TestController
{
    [HttpPost]
    [ValidateInput(false)]
    public ActionResult ControllerMethod(string input) {
        return f(input);
    }
}

解決方案

雖然它執行黑名單(從定義上來說比白名單更差)並且您不應該僅僅依靠它來進行 XSS 保護,但它為您的應用程式提供了第一道防線。不要停用驗證:

public class TestController
{
    [HttpPost]
    public ActionResult ControllerMethod(string input) {
        return f(input);
    }
}

在顯示或使用使用者提供的資料(即使是從資料庫載入的)之前,請務必使用適當的編碼器(Html、Url 等)。

參考

CWE-554:ASP.NET 設定錯誤:未使用輸入驗證框架
MSDN:ASP.NET 中的請求驗證
OWASP:ASP.NET 請求驗證
請參閱XSS參考。

 SCS0021 - 請求驗證已停用(設定檔) 

validateRequest在設定檔中停用了提供針對XSS 的額外保護

風險

跨站腳本

易受攻擊的程式碼

<system.web>
   ...
   <pages [..] validateRequest="false" [..]/>
   ...
</system.web>

解決方案

雖然它執行黑名單(從定義上來說比白名單更差)並且您不應該僅僅依靠它來進行 XSS 保護,但它為您的應用程式提供了第一道防線。不禁用驗證:預設值為true。或明確設定:

<system.web>
   ...
   <pages [..] validateRequest="true" [..]/>
   ...
</system.web>

參考

CWE-554:ASP.NET 設定錯誤:未使用輸入驗證框架
MSDN:pages 元素(ASP.NET 設定架構)
MSDN:ASP.NET 中的請求驗證
OWASP:ASP.NET 請求驗證
請參閱XSS參考。

 SCS0030 - 僅對頁面啟用請求驗證(設定檔) 

提供對XSS 的requestValidationMode額外保護僅針對頁面啟用,而不是針對設定檔中的所有 HTTP 請求啟用。

風險

跨站腳本

易受攻擊的程式碼

<system.web>
   ...
   <httpRuntime [..] requestValidationMode="2.0" [..]/>
   ...
</system.web>

解決方案

<system.web>
   ...
   <httpRuntime [..] requestValidationMode="4.5" [..]/>
   ...
</system.web>

參考

CWE-554:ASP.NET 設定錯誤:未使用輸入驗證框架
MSDN:pages 元素(ASP.NET 設定架構)
MSDN:ASP.NET 中的請求驗證
OWASP:ASP.NET 請求驗證
MSDN:RequestValidationMode 屬性
請參閱XSS參考。

密碼管理

 SCS0015 - 硬編碼密碼 

此 API 的密碼配置似乎是硬編碼的。

風險

如果使用硬編碼密碼,那麼惡意使用者幾乎肯定會透過相關帳戶獲得存取權限。

易受攻擊的程式碼

config.setPassword("NotSoSecr3tP@ssword");

解決方案

建議將密碼等配置外部化,避免機密資訊外洩。與生產配置相比,原始碼或其二進位形式更容易被攻擊者存取。為了安全管理,密碼和金鑰應以加密形式儲存在單獨的設定檔中。解密憑證應以不可匯出的形式安裝在伺服器電腦上。

設定檔:

<configuration>
    <appSettings>
    <add key="api_password" value="b3e521073ca276dc2b7caf6247b6ddc72d5e2d2d" />
  </appSettings>
</configuration>

代碼:

string apiPassword = ConfigurationManager.AppSettings["api_password"];
config.setPassword(apiPassword);

參考

CWE-259:使用硬編碼密碼

 SCS0034 - 未設定密碼要求長度 

RequiredLength 屬性必須設定為最小值 8。

風險

弱密碼可能會被猜測或暴力破解。

易受攻擊的程式碼

ASP.NET Identity 預設值為 6。

PasswordValidator pwdv = new PasswordValidator();

解決方案

查看密碼複雜性的解決方案

參考

CWE-521:弱密碼需求
MSDN:ASP.NET Identity PasswordValidator 類

 SCS0032 - 密碼要求長度太小 

建議密碼的最小長度至少設定為8位。

風險

弱密碼可能會被猜測或暴力破解。

易受攻擊的程式碼

PasswordValidator pwdv = new PasswordValidator
{
    RequiredLength = 6,
};

解決方案

查看密碼複雜性的解決方案

參考

CWE-521:弱密碼需求
MSDN:ASP.NET Identity PasswordValidator 類

 SCS0033 - 密碼複雜性 

為了提高安全性,PasswordValidator 至少應該有兩個要求(RequiredLength、RequireDigit、RequireLowercase、RequireUppercase 和/或 RequireNonLetterOrDigit)。

風險

弱密碼可能會被猜測或暴力破解。

易受攻擊的程式碼

PasswordValidator pwdv = new PasswordValidator
{
    RequiredLength = 6,
};

解決方案

PasswordValidator pwdv = new PasswordValidator
{
    RequiredLength = 8,
    RequireNonLetterOrDigit = true,
    RequireDigit = true,
    RequireLowercase = true,
    RequireUppercase = true,
};

參考

CWE-521:弱密碼需求
MSDN:ASP.NET Identity PasswordValidator 類

其他

 SCS0011 - 使用了不安全的 XSLT 設置 

僅當您需要腳本支援並且在完全受信任的環境中工作時才應啟用 XSLT 腳本。

風險

如果 XML 來源不受信任,則此問題可能會導致遠端程式碼執行 (RCE)。

易受攻擊的程式碼

XslCompiledTransform transform = new XslCompiledTransform();
XsltSettings settings = new XsltSettings() {EnableScript = true};
transform.Load(xslPath, settings, null);
// Execute the transformation.
transform.Transform(reader, writer);

參考

CWE-611:XML 外部實體引用
XSLT 伺服器端注入攻擊
XML 攻擊 C# 遠端程式碼執行
XsltSettings.EnableScript 屬性的不當限制

 SCS0012 - 控制器方法可能容易受到授權繞過的影響 

註 [Authorize] 和 [AllowAnonymous] 均不存在。

風險

未經授權的使用者可能會存取該端點。如果它包含敏感資訊,例如日誌文件,則可能會導致權限提升。如果應用程式正在使用其他授權檢查,則可能會忽略/抑制該警告。可以規則並註冊附加屬性。

易受攻擊的程式碼

public class AccountController : Controller
{
   public ActionResult Login()
   {
   }

   [Authorize]
   public ActionResult Logout()
   {
   }
}

解決方案

[Authorize]
public class AccountController : Controller
{
    [AllowAnonymous]
    public ActionResult Login()
    {
    }

    public ActionResult Logout()
    {
    }
}

參考

CWE-284:不當存取控制
存取控制漏洞和權限提升
ASP.NET Core 中的簡單授權

 SCS0016 - 跨站請求偽造 (CSRF) 

防偽標記遺失。

風險

攻擊者可以向受害者發送連結。透過訪問惡意鏈接,網頁將觸發對網站的 POST 請求(因為這是一種盲目攻擊 - 攻擊者看不到觸發請求的回應,也不會使用 GET 請求,而且根據定義,GET 請求不應該改變伺服器上的狀態)。受害者無法確認後台執行的操作,但如果他透過網站驗證,他的 cookie 就會自動提交。除了訪問網站之外,此攻擊不需要任何特殊互動。

易受攻擊的程式碼

public class TestController
{
    [HttpPost]
    public ActionResult ControllerMethod(string input)
    {
        //Do an action in the context of the logged in user
    }
}

解決方案

您認為:

@Html.AntiForgeryToken()

在您的控制器中:

public class TestController
{
    [HttpPost]
    [ValidateAntiForgeryToken] //Annotation added
    public ActionResult ControllerMethod(string input)
    {
        //Do an action in the context of the logged in user
    }
}

參考

CWE-352:跨站請求偽造 (CSRF)
OWASP:跨站請求偽造
OWASP:CSRF 預防備忘單

 SCS0019 - 輸出快取衝突 

快取與授權衝突。

風險

使用註解 [OutputCache] 將停用第一個請求之後的註解 [Authorize]。

易受攻擊的程式碼

[Authorize]
public class AdminController : Controller
{
    [OutputCache]
    public ActionResult Index()
    {
        return View();
    }
}

解決方案

刪除快取:

[Authorize]
public class AdminController : Controller
{
    public ActionResult Index()
    {
        return View();
    }
}

參考

CWE-524:使用包含敏感資訊的快取
透過輸出快取提高效能

 SCS0022 - 事件驗證已停用 

在設定檔中被enableEventValidation停用。

風險

此功能降低了未經授權或惡意的回發請求和回呼的風險。強烈建議您不要停用事件驗證。當 EnableEventValidation 屬性設定為 true 時,ASP.NET 會驗證控制項事件是否源自於該控制項呈現的使用者介面。

易受攻擊的程式碼

<system.web>
   ...
   <pages [..] enableEventValidation="false" [..]/>
   ...
</system.web>

解決方案

預設值為 secure- true。或明確設定:

<system.web>
   ...
   <pages [..] enableEventValidation="true" [..]/>
   ...
</system.web>

參考

CWE-554:ASP.NET 設定錯誤:未使用輸入驗證框架
MSDN:pages 元素(ASP.NET 設定架構)
MSDN:Page.EnableEventValidation 屬性

 SCS0027-開放重定向 

傳遞給的動態值Redirect應該被驗證。

風險

您的網站可能被用於網路釣魚攻擊。攻擊者可能會製作一個看似可信的連結指向您的網站,將受害者重新導向到類似的惡意網站:https://www.yourdomain.com/loginpostback?redir=https://www.urdomain.com/login

易受攻擊的程式碼

[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 form
    return 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 form
    return View(model);
}

參考

CWE-601:URL 重定向至不受信任的網站(「開放重定向」)
Microsoft:防止開放重定向攻擊 (C#)
OWASP:未經驗證的重定向和轉送備忘單
Hacksplaining:防止惡意重定向

 SCS0028 - 不安全的反序列化 

傳遞了不受信任的資料以進行反序列化。

風險

任意程式碼執行、完全應用程式破壞或拒絕服務。攻擊者可能會傳遞特製的特定類別的序列化 .NET 對象,該物件將在物件建構期間執行惡意程式碼。

易受攻擊的程式碼

private void ConvertData(string json)
{
    var mySerializer = new JavaScriptSerializer(new SimpleTypeResolver());
    Object mything = mySerializer.Deserialize(json, typeof(SomeDataClass)/* the type doesn't matter */);
}

解決方案

沒有簡單的解決方法。不要反序列化不受信任的資料:使用者輸入、cookie 或跨越信任邊界的資料。

如果不可避免:
1)如果在伺服器端進行序列化,則跨越信任邊界,但未被修改並傳回(例如 cookie) - 使用簽章加密(例如 HMAC)來確保它沒有被竄改。
2)不要從不受信任的來源取得反序列化的類型:序列化流本身或其他不受信任的參數。BinaryFormatter例如從序列化流本身讀取類型信息,不能與不受信任的流一起使用:

// DO NOT DO THIS!
var thing = (MyType)new BinaryFormatter().Deserialize(untrustedStream);

例如,沒有 JavaScriptTypeResolver 的 JavaScriptSerializer 是安全的,因為它根本不會解析類型:

private void ConvertData(string json)
{
    var mySerializer = new JavaScriptSerializer(/* no resolver here */);
    Object mything = mySerializer.Deserialize(json, typeof(SomeDataClass));
}

將預期類型(可能是硬編碼)傳遞給反序列化庫。一些函式庫(如 Json.Net、DataContractJsonSerializer 和 FSPickler)在反序列化之前驗證預期的物件圖。但是,如果預期類型包含System.Object層次結構中嵌套的欄位或屬性,則檢查不是萬無一失的。

// Json.net will inspect if the serialized data is the Expected type
var 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 executed
var thing = (MyType)new BinaryFormatter().Deserialize(untrustedStream);

3)如果庫支援實現回調,則驗證物件及其屬性是否屬於預期類型(不要黑名單,使用白名單!):

class LimitedBinder : SerializationBinder
{
    List<Type> allowedTypes = new List<Type>()
    {
        typeof(Exception),
        typeof(List<Exception>),
    };

    public override 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.
        throw new Exception("Unexpected serialized type");
    }
}

var formatter = new BinaryFormatter() { Binder = new LimitedBinder () };
var data = (List<Exception>)formatter.Deserialize (fs);

確定哪些類型是安全的非常困難,除非必要,否則不建議採用這種方法。如果從不信任的資料反序列化,則有許多類型可能允許非遠端程式碼執行漏洞。拒絕服務尤其常見。例如,System.Collections.HashTable 類別從不受信任的流中反序列化是不安全的——流可以指定內部「儲存桶」數組的大小並導致記憶體不足的情況。

4)僅序列化簡單資料傳輸物件(DTO) 。不要序列化/反序列化類型資訊。例如,TypeNameHandling.None在 Json.net 中僅使用(預設):

class DataForStorage
{
    public string Id;
    public int    Count;
}

var data = JsonConvert.SerializeObject<DataForStorage>(json, new
JsonSerializerSettings
{
    TypeNameHandling = TypeNameHandling.None
});

將產生以下不帶類型資訊的 JSON,但可以完全反序列化回來:

{
  "Id": null,
  "Count": 0
}

參考

CWE-502:不受信任資料的反序列化
BlackHat USA 2017:13號星期五:JSON 攻擊
BlueHat v17:危險內容 - 保護 .Net 反序列化
BlackHat USA 2012:你是我喜歡的類型嗎?
OWASP:不受信任資料的反序列化
,適用於各種 .NET 格式化程式的反序列化有效負載產生器,
.NET 反序列化被動掃描器


資料來源:https://security-code-scan.github.io/