Adam here.
I’ve learned to love STRIDE as a framework for thinking about threats, but it makes a lousy classification system. That is, I can look at a system to find information disclosure threats, but once I have an attack that leaks, say, the location of a DLL in memory to a remote attacker, is that Information Disclosure or Elevation of Privilege? It’s likely to make the latter easy, and down the classification rat-hole we go. I’d like to suggest that calling it ‘the STRIDE framework is the most clear wording we can use.’
I found the 1999 internal Microsoft article written by (then) Microsoft employees Loren Kohnfelder and Praerit Garg, and was pleased to discover that they intended STRIDE “to help you identify potential vulnerabilities in your product during a security analysis.” They also make repeated reference to a “proactive security analysis process,” and shows some of the thinking that led to the SDL. I thought it was neat look into history, and so without further ado, it's attached. (59KB .docx)
Hi, Bryan here.
For any of you that might not have seen the movie Sneakers, I’ll try to not spoil the plot completely for you, but the main storyline revolves around a “little black box” that a scientist has developed that can automatically defeat asymmetric encryption. It’s a fun movie, but what if this happened in real life? After all, crypto algorithms are broken all the time – either through little black box cleverness or simply through improved access to brute force processing power. If RSA, AES, SHA-2 or any of the other current SDL crypto standard algorithms were to be broken tomorrow, what kind of changes would you have to make to your applications? If you’ve hardcoded that algorithm into your apps, you’ll probably have to make some emergency code changes to use a new algorithm, issue patches to all of your users, and then hope that the new algorithm you chose doesn’t also get compromised. However, there is a better way to handle this scenario.
The SDL requires all applications to be able to upgrade the algorithms they use over time. This is usually referred to as the SDL crypto agility requirement. Both the .NET framework and the Cryptography API: Next Generation (CNG) include some useful features that can help you make your code more cryptographically agile; in fact, if you write your application the right way, you’ll be able to change algorithms with simple configuration file edits – no code changes required.
For .NET code, the first step in crypto agility is to avoid hardcoding any particular algorithm or algorithm implementation into your code, and instead refer only to the abstract class of algorithm you need. Instead of instantiating a SHA256CryptoServiceProvider object (for example), you would declare an abstract HashAlgorithm. Instead of instantiating an AesManaged object, you would declare an abstract SymmetricAlgorithm. You can’t instantiate an abstract class, but System.Security.Cryptography abstract algorithm classes expose static Create methods. So instead of this code:
SHA512Cng sha = new SHA512Cng(); // not agile!
You would use this code:
HashAlgorithm hash = HashAlgorithm.Create(“SHA512”); // more agile
This new code doesn’t look any better than the old code – it looks like we’ve still hardcoded SHA512 into the application. But we actually haven’t; we’ve only hardcoded the string “SHA512” into the application, and we can edit the machine.config file to redefine which class actually gets instantiated when an application tries to create a “SHA512” object.
An even better alternative is to define application-specific configuration strings and write these both into the code and into the machine.config files of systems where the app is deployed. This is safer than redefining a common algorithm string like “SHA512”, because you can upgrade the algorithm used by an individual application without affecting any other apps:
HashAlgorithm hash = HashAlgorithm.Create(“MyApplication_PreferredHash”); // most agile
If you’re writing native C++ code, you can accomplish the same goal with CNG. Again, the first step is to avoid hardcoding algorithm names into your code:
BCRYPT_ALG_HANDLE hAlg = NULL;NTSTATUS ret = BCryptOpenAlgorithmProvider(&hAlg, L"SHA256", NULL, 0); // not agile!
Instead, load the desired algorithm provider string from a configuration file, or the registry, or some other location. Just be sure to apply an appropriate ACL to the resource where you’re storing your setting! You don’t want unauthorized users reducing the security strength of the application by reconfiguring it to use a weaker algorithm.
LPCWSTR algName = NULL;// load desired algName from the registry…NTSTATUS ret = BCryptOpenAlgorithmProvider(&hAlg, algName, NULL, 0); // more agile
In most cases, some additional work will be required in order to make crypto agility code work correctly. For example, if you’re storing password hashes for an authentication system, you can’t change just the comparing algorithm and expect the system to work. If the stored hashes are MD5 and you start comparing them to computed SHA-2 hashes, no one will be able to log in. In this case, you’ll need to store metadata about the algorithm used along with the stored password hash. When authenticating the user, instantiate the exact algorithm they originally used to create the password hash. Once they’ve authenticated, check whether the algorithm used to create their hash is out of date. If so, prompt them to create a new password, then create and store the new password hash using the new preferred algorithm.
Of course, this example is just the tip of the iceberg. If you’re interested in reading more about crypto agility, including more code and configuration samples, be sure to check out the Security Briefs column of the current MSDN Magazine, the Cryptographic Enhancements chapter of Writing Secure Code for Windows Vista, or Shawn Farkas’ (of the CLR Security team) blog. As always, questions and comments are welcome.
Hello, Michael here.
A word of warning, this is purely an “FYI” post that has very little to do with SDL policy!
I get this question, “How do I call various SDL-mandated APIs before my code starts?” about once a month, so I decided to write about it so I don’t have keep dragging up the same email over and over! The question roughly translates into “Can I call some setup code before main() starts?”
The answer is ‘yes’! But why would you want to do it? One reason is perhaps you want to call the SetProcessDEPPolicy API because you don’t have access to a compiler with the /NXCOMPAT option, or perhaps you want to call HeapSetInformation very early in your code because main() handles untrusted data. Or perhaps you want to create a library for your developers to link with and not require them to add new API calls to their code. But probably the most important reason is if you want to update many EXEs but don’t want to change the code, all you need to do is link with the OBJ file. That’s it!
Visual C++ allows you to define your own code sections that are called by the C startup runtime code prior to calling main(). The following code snippet could be compiled to a .OBJ and then linked with your C or C++ project and will call the SetProcessDEPPolicy API to set the NX bit on your process. You can add most any API in here.
static int __cdecl SDLSetup(void) {
HeapSetInformation(NULL, HeapEnableTerminationOnCorruption, NULL, 0);
HMODULE hmodKernel32 = GetModuleHandleW(L"KERNEL32.DLL");
BOOL (WINAPI *pfnSetProcessDEPPolicy)(DWORD);
*(FARPROC *) &pfnSetProcessDEPPolicy
= GetProcAddress(hmodKernel32, "SetProcessDEPPolicy");
if (pfnSetProcessDEPPolicy != 0)
(*pfnSetProcessDEPPolicy)
(PROCESS_DEP_ENABLE | PROCESS_DEP_DISABLE_ATL_THUNK_EMULATION);
return(0);
}
static __declspec(allocate(".CRT$XIAA")) int (__cdecl *pfnSDLSetup)(void) = &SDLSetup;