Security Training: #4 Development: Typical Security Issues

4,108 views

Published on

Published in: Technology
0 Comments
0 Likes
Statistics
Notes
  • Be the first to comment

  • Be the first to like this

No Downloads
Views
Total views
4,108
On SlideShare
0
From Embeds
0
Number of Embeds
3
Actions
Shares
0
Downloads
0
Comments
0
Likes
0
Embeds 0
No embeds

No notes for slide
  • Each of the above is useful and necessary to ensure the overall security of thesite, but they address different risks.Firewalls protect a system from a different class of risks by preventing accessto non-public services and preventing malicious network traffic to reach theserver. SSL provides server (and sometimes client) authentication andcommunication privacy, but otherwise it’s blind to the content of the traffic.File permissions may prevent abuses of rights when two different user levelsare involved but it will not do so between two users with the same level.To draw a parallel to the traditional development, coding for security would bevery roughly equivalent to putting error handling. It’s got to be in,nothingaround the application can replace it.This is not about how to do web development. It’s specifically about how todo secure web development. Why is this emphasis relevant? Because creatingan application able to withstand malicious use (and we’ll see later what thiscould mean) is not something that (a) is immediately visible; a non-securecode can do its primary functionality very well (b) has been a concern duringdevelopment phases (c) taught in programming books or seen in traditionaldevelopment projects when the user community was limited and notparticularly hacker populated.No. Within the context of this document, security needs to be built into theapplication from the beginning, it’s not something that’s applied at the end.Of course, we’ll still have permissions and other administrative operations,but again, they are not a replacement.It's encrypted, so it's secure. Encryption is not security. Take a simple example like email. Most people turn on the SSL/TLS settings for their email clients, then proceed under the false assumption that their message is secure. The data is at rest in the clear on the clients and servers, however, and is far from safe. Most Web sites use SSL for "secure" transactions, but obviously we still have Web server hacking and SQL injections, etc. In this case, SSL may actually help the attacker hide from defense systems, which cannot always see through the encryption. Bottom line: it is possible to design a secure system without encryption, and it is all too easy to design a highly vulnerable system that employs strong encryption. No one knows my algorithm, so it must be secure. I think what you meant to say is "No one knows my algorithm yet." Precious few algorithms have survived the trials of reverse engineering and cryptanalysis. Take for example the key generators for pirated software, or the satellite TV hacking tribulations. You are indeed safer as long as no one knows your software code and algorithms, but if you use that situation as the only line of defense, than you are doomed. Secrecy, obscurity, and obfuscation are valid tools, but only when used in concert with a secure design. Once a piece of code is deemed secure in one system, is secure for use everywhere. The best example I ever heard of why this is false comes from an old manager and compatriot in the war against bad security-related assumptions. He described a simple keypad interface driver, whereby keypresses were buffered in memory to allow for you to enter the numbers in a sequence. Think of your garage door keypad where your code is 1111. It usually will let you type 09811119876 or 11122221111 or similar, as long as 1111 is in there somewhere. No problems here. Now take that same piece of code and put it in a networked security entrance panel, or an ATM. Ooops. You inadvertently left the code in memory for a hacker to steal, long with some other more subtle problems. Organizations that develop "secure" libraries that have been tested for use in "secure" system across multiple product lines often undertake such efforts in vain. Use cases and assumptions must be reconsidered, and code must be reviewed and re-tested in each product, no matter how similar they may seem.
  • As the Internet grows in importance, applications are becoming highly interconnected. In the "good old days," computers were usually islands of functionality, with little, if any, interconnectivity. In those days, it didn't matter if your application was insecure—the worst you could do was attack yourself—and so long as an application performed its task successfully, most people didn't care about security. This paradigm is evident in many of the classic best practices books published in the early 1990s. For example, the excellent Code Complete (Microsoft Press, 1993), by Steve McConnell, makes little or no reference to security in its 850 pages. Don't get me wrong: this is an exceptional book and one that should be on every developer's bookshelf. Just don't refer to it for security inspiration.It's also important to remember that secure systems are quality systems. Code designed and built with security as a prime feature is more robust than code written with security as an afterthought. Secure products are also more immune to media criticism, more attractive to users, and less expensive to fix and support. Because you cannot have quality without security, you must use tact or, in rare cases, subversion to get everyone on your team to be thinking about security
  • Buffer overflow, or buffer overrun, is an anomalous condition where a process attempts to store data beyond the boundaries of a fixed-length bufferBuffer overflows can be triggered by inputs specifically designed to execute malicious code or to make the program operate in an unintended waySufficient bounds checking by either the programmer, the compiler or the runtime can prevent buffer overflowsThe programming languages most commonly associated with buffer overflows are C and C++In computer security and programming, a buffer overflow, or buffer overrun, is an anomalous condition where a process attempts to store data beyond the boundaries of a fixed-length buffer. The result is that the extra data overwrites adjacent memory locations. The overwritten data may include other buffers, variables and program flow data, and may result in erratic program behavior, a memory access exception, program termination (a crash), incorrect results or ― especially if deliberately caused by a malicious user ― a possible breach of system security.Buffer overflows can be triggered by inputs specifically designed to execute malicious code or to make the program operate in an unintended way. As such, buffer overflows cause many software vulnerabilities and form the basis of many exploits. Sufficient bounds checking by either the programmer, the compiler or the runtime can prevent buffer overflows.The programming languages most commonly associated with buffer overflows are C and C++, because they provide no built-in protection against accessing or overwriting data in any part of memory and do not check that data written to an array (the built-in buffer type) is within the boundaries of that array.Stack Overruns: These type of buffer overruns occur, when a buffer that is declared on the stack is overwritten by copying more data than the buffer can hold. It so happens, that the variables (buffer in this case) declared on the stack are located next to the return address of the function?s caller (this is what we have discussed above). As I mentioned above, this usually occurs when user input is unchecked, e.g. strcat. And because the return address is next to the buffer on the stack, overwriting the buffer, means overwriting the return address, which is what gets executed with the function returns. An attacker can carefully exploit the overrun in such a way the data that is overwriting the return address, is an address of a function that he wants to execute. Heap Overruns: Like Stack Overruns, Heap overruns can also cause memory and stack corruption. But unlike contrary developer belief, although heap overruns are harder to exploit, they are definitely exploitable.A heap overflow is a type of buffer overflow that occurs in the heap data area. Memory on the heap is dynamically allocated by the application at run-time and typically contains program data.A heap overrun is much the same problem as a stack-based buffer overrun, but it's somewhat trickier to exploit. As in the case of a stack-based buffer overrun, your attacker can write fairly arbitrary information into places in your application that she shouldn't have access to. One of the best articles I've found is w00w00 on Heap Overflows, written by Matt Conover of w00w00 Security Development (WSD). You can find this article at http://www.w00w00.org/files/articles/heaptut.txt. WSD is a hacker organization that makes the problems they find public and typically works with vendors to get the problems fixed. The article demonstrates a number of the attacks they list, but here's a short summary of the reasons heap overflows can be serious:Many programmers don't think heap overruns are exploitable, leading them to handle allocated buffers with less care than static buffers.Some operating systems and chip architectures can be configured to have a nonexecutable stack. Once again, this won't help you against a heap overflow because a nonexecutable stack protects against stack-based attacks, not heap-based attacks.Tools exist to make stack-based buffer overruns more difficult to exploit. StackGuard, developed by Crispin Cowan and others, uses a test value—known as a canary after the miner's practice of taking a canary into a coal mine—to make a static buffer overrun much less trivial to exploit. Visual C++ .NET incorporates a similar approach. Similar tools do not currently exist to protect against heap overruns.Array Indexing Errors (Overruns and Underruns): These type of errors are less exploited compared to static buffer overruns. You can think of an array as a block on memory (buffer) that you can index into and then read/write from that location. Bad array implementation do not check indices well before access the memory locations. Sloppy code like this can be exploited to run arbitrary code and create havoc. (Well, in some cases you may never ever now that your machine is freely accessible and controlled by the attacker ). Again, unlike contrary developer belief, don?t be fooled that only memory past the end of the array can be exploited.Array indexing errors are much less commonly exploited than buffer overruns, but it amounts to the same thing—a string is just an array of characters, and it stands to reason that arrays of other types could also be used to write to arbitrary memory locationsArray indexing error would allow you to write to memory locations not only higher than the base of the arrayThe typical way to get hacked with this sort of error occurs when the user tells you how many elements to expect and is allowed to randomly access the array once it’s created because you’ve failed to enforce bounds checkingA related problem is that of truncation error. To a 32-bit operating system, 0x100000000 is really the same value as 0x00000000Be very careful when dealing with anything that could result in either a truncation error or an overflowFormat Strings Exploits: These type of exploits are not exactly buffer overruns, but they lead to the same class of problems. These errors are usually caused in functions that take in variable number of arguments, because there isn?t a good way for the function to determine the number of arguments passed into these functions. (printf family in the CRT). The %n type field for printf represents the number of characters successfully written so far to the stream or buffer. This value is stored in the integer whose address is given as the argument. So, this can basically be used to write into memory of the processes address space. But how can an attacker inject such code, the answer lies to the way the sloppy programmer writes code ala printf(input), rather than printf(?%s?, input). The latter prevent the user from using his own format, since its already defined, unlike the earlier case, where the input can be manipulated to create the format string.Format string bugs aren’t exactly a buffer overflow, but they lead to the same problemsThe basic problem stems from the fact that there isn’t any realistic way for a function that takes a variable number of arguments to determine how many arguments were passed inExploiting such bugs on Windows systems is a little difficult than on Unix systemsThe fix to the problem is relatively simple: always pass in a format string to the printf family of functions. For example, printf(input) is exploitable, and printf("%s", input) is not exploitableTake special care if you have custom format strings stored to help with versions of your application in different languages and make sure that the strings can’t be written by unprivileged users
  • The buffer overrun caused by Unicode and ANSI buffer size mismatches is somewhat common on Windows platforms. It occurs if you mix up the number of elements with the size in bytes of a Unicode buffer. There are two reasons it’s rather widespread: Windows NT and later support ANSI and Unicode strings, and most Unicode functions deal with buffer sizes in wide characters, not byte sizes.The most commonly used function that is vulnerable to this kind of bug is MultiByteToWideChar.A Real Unicode Bug ExampleThe Internet Printing Protocol (IPP) buffer overrun vulnerability was a Unicode bug. You can find out more information on this vulnerability at www. microsoft.com/technet/security; look at bulletin MS01-23. IPP runs as an ISAPI filter in Internet Information Services (IIS) 5, which runs under the SYSTEM account—therefore, an exploitable buffer overrun is even more dangerous. Notice that the bug was not in IIS.
  • The first line of defense is simply to write solid code! Although some aspects of writing secure code are a little arcane, preventing buffer overruns is mostly a matter of writing a robust application. Writing Solid Code (Microsoft Press, 1993), by Steve Maguire, is an excellent resource. Even if you’re already a careful, experienced programmer, this book is still worth your time.Always validate all your inputs—the world outside your function should be treated as hostile and bent upon your destruction. Likewise, nothing about the function’s internal implementation, nothing other than the function’s expected inputs and output, should be accessible outside the function. Choice of programming languageThe choice of programming language can have a profound effect on the occurrence of buffer overflows. As of 2008, among the most popular languages are C and its derivative, C++, with an enormous body of software having been written in these languages. C and C++ provide no built-in protection against accessing or overwriting data in any part of memory; more specifically, they do not check that data written to an array (the implementation of a buffer) is within the boundaries of that array. However, the standard C++ libraries provide many ways of safely buffering data, and technology to avoid buffer overflows also exists for C.Many other programming languages provide runtime checking and in some cases even compile-time checking which might send a warning or raise an exception when C or C++ would overwrite data and continue to execute further instructions until erroneous results are obtained which might or might not cause the program to crash. Examples of such languages include Ada, Lisp, Modula-2, Smalltalk, OCaml and such C-derivatives as Cyclone and D. The Java and .NETbytecode environments also require bounds checking on all arrays. Nearly every interpreted language will protect against buffer overflows, signalling a well-defined error condition. Often where a language provides enough type information to do bounds checking an option is provided to enable or disable it. Static code analysis can remove many dynamic bound and type checks, but poor implementations and awkward cases can significantly decrease performance. Software engineers must carefully consider the tradeoffs of safety versus performance costs when deciding which language and compiler setting to use.Safe String HandlingString handling is the single largest source of buffer overruns, so a review of the commonly used functions is in order. Although I’m going to cover the single-byte versions, the same problems apply to the wide-character string-handling functions. To complicate matters even further, Windows systems support lstrcpy, lstrcat, and lstrcpyn, and the Windows shell contains similar functions, such as StrCpy, StrCat, and StrCpyN exported from Shlwapi.dll. Although the lstr family of calls varies a little in the details and the calls work with both single-byte and multibyte character sets depending on how an LPTSTR ends up being defined by the application, they suffer from the same problems as the more familiar ANSI versions.Standard Template Library StringsOne of the coolest aspects of writing C++ code is using the Standard Template Library (STL). The STL has saved me a lot of time and made me much more efficient. The STL also has several really useful member functions you can use to find characters and strings within another string and truncate the string. It comes in a wide-character version too. Microsoft Foundation Classes (MFC) CStrings work almost exactly the same way.Use of safe librariesThe problem of buffer overflows is common in the C and C++ languages because they expose low level representational details of buffers as containers for data types. Buffer overflows must thus be avoided by maintaining a high degree of correctness in code which performs buffer management. It has also long been recommended to avoid standard library functions which are not bounds checked, such as gets, scanf and strcpy. The Morris worm exploited a gets call in fingerd.[13]Well-written and tested abstract data type libraries which centralize and automatically perform buffer management, including bounds checking, can reduce the occurrence and impact of buffer overflows. The two main building-block data types in these languages in which buffer overflows commonly occur are strings and arrays; thus, libraries preventing buffer overflows in these data types can provide the vast majority of the necessary coverage. Still, failure to use these safe libraries correctly can result in buffer overflows and other vulnerabilities; and naturally, any bug in the library itself is a potential vulnerability. "Safe" library implementations include "The Better String Library" [14], Vstr[15] and Erwin.[16] The OpenBSDoperating system's C library provides the strlcpy and strlcat functions, but these are more limited than full safe library implementations.In September 2006, Technical Report 24731, prepared by the C standards committee, was published; it specifies a set of functions which are based on the standard C library's string and I/O functions, with additional buffer-size parameters. However, the efficacy of these functions for the purpose of reducing buffer overflows is disputable; it requires programmer intervention on a per function call basis that is equivalent to intervention that could make the analogous older standard library functions buffer overflow safe.[17]Stack-smashing protectionStack-smashing protection is used to detect the most common buffer overflows by checking that the stack has not been altered when a function returns. If it has been altered, the program exits with a segmentation fault. Three such systems are Libsafe,[18] and the StackGuard[19] and ProPolice[20]gcc patches.Microsoft's Data Execution Prevention mode explicitly protects the pointer to the SEH Exception Handler from being overwritten.[21]Stronger stack protection is possible by splitting the stack in two: one for data and one for function returns. This split is present in the Forth programming language, though it was not a security-based design decision. Regardless, this is not a complete solution to buffer overflows, as sensitive data other than the return address may still be overwritten.Pointer protectionBuffer overflows work by manipulating pointers (including stored addresses). PointGuard was proposed as a compiler-extension to prevent attackers from being able to reliably manipulate pointers and addresses.[22] The approach works having the compiler add code to automatically XOR-encode pointers before and after they are used. Because the attacker (theoretically) does not know what value will be used to encode/decode the pointer, he cannot predict what it will point to if he overwrites it with a new value. PointGuard was never released, but Microsoft implemented a similar approach beginning in Windows XP SP2 and Windows Server 2003 SP1.[23] Rather than implement pointer protection as an automatic feature, Microsoft added an API routine that can be called at the discretion of the programmer. This allows for better performance (because it is not used all of the time), but places the burden on the programmer to know when it is necessary.Because XOR is linear, an attacker may be able to manipulate an encoded pointer by overwriting only the lower bytes of an address. This can allow an attack to succeed if the attacker is able to attempt the exploit multiple times and/or is able to complete an attack by causing a pointer to point to one of several locations (such as any location within a NOP sled)[24]. Microsoft added a random rotation to their encoding scheme to address this weakness to partial overwrites.[25]Executable space protectionExecutable space protection is an approach to buffer overflow protection which prevents execution of code on the stack or the heap. An attacker may use buffer overflows to insert arbitrary code into the memory of a program, but with executable space protection, any attempt to execute that code will cause an exception.Executable space protection does not generally protect against return-to-libc attacks, or any other attack which does not rely on the execution of the attackers code. However, on 64-bit systems using ASLR, as described below, executable space protection makes it far more difficult to execute such attacks.Address space layout randomizationAddress space layout randomization (ASLR) is a computer security feature which involves arranging the positions of key data areas, usually including the base of the executable and position of libraries, heap, and stack, randomly in a process' address space.Randomization of the virtual memory addresses at which functions and variables can be found can make exploitation of a buffer overflow more difficult, but not impossible. It also forces the attacker to tailor the exploitation attempt to the individual system, which foils the attempts of internet worms.[32] A similar but less effective method is to rebase processes and libraries in the virtual address space.Deep packet inspectionThe use of deep packet inspection (DPI) can detect, at the network perimeter, very basic remote attempts to exploit buffer overflows by use of attack signatures and heuristics. These are able to block packets which have the signature of a known attack, or if a long series of No-Operation instructions (known as a nop-sled) is detected, these were once used when the location of the exploit's payload is slightly variable.Packet scanning is not an effective method since it can only prevent known attacks and there are many ways that a 'nop-sled' can be encoded. Attackers have begun to use alphanumeric, metamorphic, and self-modifyingshellcodes to evade detection by heuristic packet scanners and Intrusion detection systems.Stacks that grow upWithin the topic of stack buffer overflows an often discussed but rarely seen architecture is one in which the stack grows in the opposite direction. This change in architecture is frequently suggested as a solution to the stack buffer overflow problem because any overflow of a stack buffer that occurs within the same stack frame can not overwrite the return pointer. Further investigation of this claimed protection finds it to be a naïve solution at best. Any overflow that occurs in a buffer from a previous stack frame will still overwrite a return pointer and allow for malicious exploitation of the bug. For instance, in the example above, the return pointer for foo will not be overwritten because the overflow actually occurs within the stack frame for strcpy. However, because the buffer that overflows during the call to strcpy resides in a previous stack frame, the return pointer for strcpy will have a numerically higher memory address than the buffer. This means that instead of the return pointer for foo being overwritten, the return pointer for strcpy will be overwritten. At most this means that growing the stack in the opposite direction will change some details of how stack buffer overflows are exploitable, but it will not reduce significantly in the number of exploitable bugs.Protection schemesOver the years a number of schemes have been developed to inhibit malicious stack buffer overflow exploitation. These usually have taken one of two forms. The first method is to detect that a stack buffer overflow has occurred and thus prevent redirection of the instruction pointer to malicious code. The second attempts to prevent the execution of malicious code from the stack without directly detecting the stack buffer overflow.Stack canariesStack canaries, so named because they operate as a canary in a coal mine so to speak, are used to detect a stack buffer overflow before execution of malicious code can occur. This method works by placing a small integer, the value of which is randomly chosen at program start, in memory just before the stack return pointer. Most buffer overflows overwrite memory from lower to higher memory addresses, so in order to overwrite the return pointer (and thus take control of the process) the canary value must also be overwritten. This value is checked to make sure it has not changed before a routine uses the return pointer on the stack. This technique can greatly increase the difficulty of exploiting a stack buffer overflow because it forces the attacker to gain control of the instruction pointer by some nontraditional means such as corrupting other important variables on the stack.Nonexecutable stackAnother approach to preventing stack buffer overflow exploitation is to enforce memory policy on stack memory region to disallow execution from the stack. This means that in order to execute shellcode from the stack an attacker must either find a way to disable the execution protection from memory, or find a way to put his shellcode payload in a non-protected region of memory. This method is becoming more popular now that hardware support for the no-execute flag is available in most desktop processors. While this method definitely makes the canonical approach to stack buffer overflow exploitation fail it is not without its problems. First it is common to find ways to store shellcode in unprotected memory regions like the heap, and so very little need change in the way of exploitation. Even if this were not so there are other ways. The most damning is the so called return to libc method for shellcode creation. In this attack the malicious payload will load the stack not with shellcode, but with a proper call stack so that execution is vectored to a chain of standard library calls, usually with the effect of disabling memory execute protections and allowing shellcode to run as normal. This works because the execution never actually vectors to the stack itself. Still if used in conjunction with techniques like ASLR a nonexecutable stack can be somewhat resistant to return to libc attacks and thus can greatly improve the security of an application
  • Each integer type in C has a fixed minimum and max-imum value that depends on the type’s machine represen-tation (e.g., two’s complement vs. one’s complement),whether the type is signed or unsigned (called “signed-ness”), and the type’s width (e.g., 16-bits vs. 32-bits). Ata high level, integer vulnerabilities arise because the pro-grammer does not take into account the maximumandmini-mum values. Integer vulnerabilities can be divided into fourcategories: overflows, underflows, truncations, and signconversion errors. Our study of 195 CVE known integervulnerabilities indicates vulnerabilities from all categoriesare prevalent in source code.Overflow. An integer overflow occurs at run-time whenthe result of an integer expression exceeds the maximumvalue for its respective type. For example, the product oftwo unsigned 8-bit integers may require up to 16-bits torepresent, e.g., 28 − 1 ∗ 28 − 1 = 65025, which cannot beaccurately represented when assigned to an 8-bit type. Of-ficially, the C99 standard specifies that a “computation in-volving unsigned operands can never overflow” because theresult can be reduced modulo the result type’s width (page34, [16]) (signed overflow is considered undefinedbehav-ior, thus implementation specific). However, overflowsarecurrently the most common integer vulnerability, account-ing for 148 of the 207 CVE vulnerabilities in our survey,indicating many programmers certainly do not understandor anticipate the C99 semantics.Figure 1(i) shows a typical overflow vulnerability inGOCR [1], an optical character recognition program forprocessing images. An attacker can exploit the program by providing large integer values to the inpam.width andinpam.heightfields. The product of these values used in the call to malloc will overflow, resulting in an erroneouslysmall allocation. The small allocation allows the exploit to write out-of-bounds through p->p, shown on the last high-lighted line.Underflow. An integer underflow occurs at run-time when the result of an integer expression is smaller than itsminimum value, thus “wrapping” to the maximum integer for the type. For example, subtracting 0 − 1 and storingthe result in an unsigned 16-bit integer will result in a value of 216 − 1, not −1. Since underflows normally occur onlywith subtraction, they are rarer than overflows, with only 10 occurrences in our survey. Figure 1(ii) shows a typicalunderflow vulnerability which occurs in Netscape versions 3.0-4.73 [3]. An attacker can specify the lenfield as 1, re-sulting in underflow in the expression len-2, thus assign-ing a large value to size. The following call to mallocwould allocate 0 bytes (due to overflow in the expression size+1), allowing the attacker to overwrite memory on thesubsequent memcpy.Signedness Error. A signedness error occurs when a signed integer is interpreted as unsigned, or vice-versa. Intwos-complement representation, such conversions cause the sign bit to be interpreted as the most significant bit(MSB) or conversely, hence -1 and 232 − 1 are misinter-preted to each other on 32-bitmachines. 44 of the 195 CVEvulnerabilities in our survey are signedness errors. Fig-ure 1 (iii) shows a signedness error from the XDR (eXternalData Representation, used by Sun RPC and NFS) routines in Linux kernel 2.4.21[2] in which the signed int size isinitialized directly from unsigned, attacker-controlled XDR data, *p. A negative size value bypasses the signed up-per bound check but is interpreted as a very large positive number by the memcpy function, whose size argument isunsigned, resulting in an instant kernel panic.Truncation. Assigning an integer with a larger width to a smaller width results in integer truncation. For exam-ple, casting an int to a short discards the leading bits of the int value, resulting in potential information loss.Figure 1(iv) shows a truncation vulnerability from the SSH CRC-32 Compensation Attack Detector [4]. The local vari-able n is only 16-bits long, so the assignment n = l can cause a truncation. By sending a very large SSH protocolpacket, an attacker can force this truncation to occur, caus-ing the xmalloc call on the next line to allocate too littlespace. The code that initializes the allocated space a few lines later will corrupt SSH’s memory, leading to an attack
  • Range CheckingAs you may have expected, the burden for integer range checking in C and C++ is placed squarely on the programmer’s shoulders. Sometimes it’s relatively easy, sometimes it’s not. It’s relatively easy, for example, to check an integer value to make sure it is within the proper range before using it to index an array. While this problem is difficult to solve, there are valid software engineering techniques that can help.First, all external inputs should be evaluated to determine whether there are identifiable upper and lower bounds. If so, these limits should be enforced by the interface. Anything that can be done to limit the input of excessively large or small integers should help prevent overflow and other type range errors. Furthermore, it is easier to find and correct input problems than it is to trace internal errors back to faulty inputs. Second, typographic conventions can be used in the code to distinguish constants from variables. They can even be used to distinguish externally influenced variables from locally used variables with well-defined ranges.Third, strong typing should be used so that the compiler can be more effective in identifying range problems.Strong TypingOne way to provide better type checking is to provide better types. Using an unsigned type, for example, can guarantee that a variable does not contain a negative value. However, this solution does not prevent overflow or solve the general case.Data abstractions can support data ranges in a way that standard and extended integer types cannot. Data abstractions are possible in both C and C++, although C++ provides more support. For example, if an integer was required to store the temperature of water in liquid form using the Fahrenheit scale, we could declare a variable as follows:unsigned char waterTemperature;Using waterTemperature to represent an unsigned 8-bit value from 1–255, is sufficient: water ranges from 32 degrees Fahrenheit (freezing) to 212 degrees Fahrenheit (the boiling point). However, this type does not prevent overflow and also allows for invalid values (that is, 1–31 and 213–255).One solution is to create an abstract type in which waterTemperature is private and cannot be directly accessed by the user. A user of this dataabstraction can only access, update, or operate on this value through public method calls. These methods must provide type safety by ensuring that the value of the waterTemperature does not leave the valid range. If this is done properly, there is no possibility of an integer type range error occurring. This data abstraction is easy to write in C++ and C. A C programmer could specify create() and destroy() methods instead of constructors and destructors but would not be able to redefine operators. Inheritance and other featuresof C++ are not required to create usable data abstractions.Compiler-Generated Runtime ChecksIn a perfect world, C and C++ compilers would flag exceptional conditions as code is generated and provide a mechanism (such as an exception, trap, or signal handler) for applications to handle these events. Unfortunately, the worldwe live in is far from perfect. A brief description of some of the capabilities that exist today follows.Visual C++. Visual C++ .NET 2003 includes native runtime checks that catch truncation errors as integers are assigned to shorter variables that result in lost data. For example, the /RTCc compiler flag catches those errors and creates a report. Visual C++ also includes a runtime_checkspragma that disables or restores the /RTC settings, but does not include flags for catching other runtime errors such as overflows.Although this seems like a useful feature, runtime error checks are not valid in a release (optimized) build, presumably for performance reasons.GCC. The gcc and g++ compilers include an -ftrapv compiler option that provides limited support for detecting integer exceptions at runtime. According to the gcc man page, this option “generates traps for signed overflow on addition, subtraction, multiplication operations.” In practice, this means that the gcc compiler generates calls to existing library functions rather than generating assembler instructions to perform these arithmetic operations on signed integers. If you use this feature, make sure you are using gcc version 3.4 or later because the checks implemented by the runtime system before this version do not adequately detect all overflows and should not be trusted.Safe Integer OperationsInteger operations can result in error conditions and possible lost data, particularly when inputs to these operations can be manipulated by a potentially malicious user.The first line of defense against integer vulnerabilities should be range checking, either explicitly or through strong typing. However, it is difficult to guarantee that multiple input variables cannot be manipulated to cause an error to occur in some operation somewhere in a program.An alternative or ancillary approach is to protect each operation. However, because of the large number of integer operations that are susceptible to these problems and the number of checks required to prevent or detect exceptional conditions, this approach can be prohibitively labor intensive and expensive to implement.A more economical solution to this problem is to use a safe integer library for all operations on integers where one or more of the inputs could be influenced by an untrusted source.Arbitrary Precision ArithmeticThere are many arbitrary precision arithmetic packages available, primarily for scientific computing. However, these can also solve the problem of integer type range errors, which result from a lack of precision in the representation.GNU Multiple Precision Arithmetic Library (GMP). GMP is a portable library written in C for arbitrary precision arithmetic on integers, rational numbers, and floating-point numbers. It was designed to provide the fastest possible arithmetic for applications that require higher precision than what is directly supported by the basic C types. GMP emphasizes speed over simplicity or elegance. It uses sophisticated algorithms, full words as the basic arithmetic type, and carefully optimized assembly code.Java BigInteger. Newer versions of the Java JDK contain a BigInteger class in the java.math package. It provides arbitrary-precision integers as well as analogs to all of Java’s primitive integer operators. While this does little for C and C++ programmers, it does illustrate that the concept is not entirely foreign to language designers.TestingChecking the input values of integers is a good start, but it does not guarantee that subsequent operations on these integers will not result in an overflow or other error condition. Unfortunately, testing does not provide any guarantees either; it is impossible to cover all ranges of possible inputs on anything but the most trivial programs.If applied correctly, testing can increase confidence that the code is secure. For example, integer vulnerability tests should include boundary conditions for all integer variables. If type-range checks are inserted in the code, test that they function correctly for upper and lower bounds. If boundary tests have not been included, test for minimum and maximum integer values for the various integer sizes used. Use white box testing to determine the types of these integer variables or, in cases where source code is not available, run tests with the various maximum and minimum values for each type.Source Code AuditSource code should be audited or inspected for possible integer range errors. When auditing, check for the following.■ Integer type ranges are properly checked.■ Input values are restricted to a valid range based on their intended use.■ Integers that cannot assume negative values (for example, ones used for indices, sizes, or loop counters) are declared as unsigned and properly range-checked for upper and lower bounds.■ All operations on integers originating from untrusted sources are performed using a safe integer library.Also, make sure that your “safe” integer library is really safe and protects against all error conditions identified or referenced in this chapter.
  • Three distinct types of XSS vulnerabilities exist: non-persistent, persistent and DOM-based (which can be either persistent or non-persistent).DOM-basedThe DOM-based or Type 0 XSS vulnerability, also referred to as local cross-site scripting, is based on the standard object model for representing HTML or XML called the Document Object Model or DOM for short. With DOM-based cross-site scripting vulnerabilities, the problem exists within a page's client-side script itself. For instance, if a piece of JavaScript accesses a URL request parameter and uses this information to write some HTML to its own page, and this information is not encoded using HTML entities, an XSS hole will likely be present, since this written data will be re-interpreted by browsers as HTML which could include additional client-side script.[18]In practice, exploiting such a hole would be very similar to the exploit of non-persistent type vulnerabilities (see below), except in one very important situation. Because of the way older versions of MSIE treat client-side script in objects located in the "local zone" (for instance, on the client's local hard drive), an XSS hole of this kind in a local page can result in remote execution vulnerabilities. For example, if an attacker hosts a malicious website, which contains a link to a vulnerable page on a client's local system, a script could be injected and would run with privileges of that user's browser on their system. (Local HTML pages are commonly installed with standard software packages, including IE.) This bypasses the entire client-side sandbox, not just the cross-domain restrictions that are normally bypassed with XSS exploits. The Local Machine Zone Lockdown in IE6 on Windows XP Service Pack 2 was implemented to prevent attackers from executing scripts in the local file zone but did not protect Internet Explorer users from similar vulnerabilities.[19]Non-PersistentThe non-persistent or Type 1 cross-site scripting hole is also referred to as a reflected vulnerability, and is by far the most common type.[21] These holes show up when data provided by a web client is used immediately by server-side scripts to generate a page of results for that user.[6] If unvalidated user-supplied data is included in the resulting page without HTML encoding, this will allow client-side code to be injected into the dynamic page.[21][6] A classic example of this is in site search engines: if one searches for a string which includes some HTML special characters, often the search string will be redisplayed on the result page to indicate what was searched for, or will at least include the search terms in the text box for easier editing. If all occurrences of the search terms are not HTML entity encoded, an XSS hole will result.[3]At first blush, this does not appear to be a serious problem since users can only inject code into their own pages. However, with a small amount of social engineering, an attacker could convince a user to follow a malicious URL which injects code into the results page, giving the attacker full access to that page's content. Due to the general requirement of the use of some social engineering in this case (and normally in Type 0 vulnerabilities as well), many programmers have disregarded these holes as not terribly important. This misconception is sometimes applied to XSS holes in general (even though this is only one type of XSS) and there is often disagreement in the security community as to the importance of cross-site scripting vulnerabilities.[22]PersistentThe persistent or Type 2 XSS vulnerability is also referred to as a stored or second-order vulnerability, and it allows the most powerful kinds of attacks. A type 2 XSS vulnerability exists when data provided to a web application by a user is first stored persistently on the server (in a database, filesystem, or other location), and later displayed to users in a web page without being encoded using HTML entities.[6] A classic example of this is with online message boards, where users are allowed to post HTML formatted messages for other users to read.[6]Persistent XSS can be more significant than other types because an attacker's malicious script is rendered more than once.[24] Potentially, such an attack could affect a large number of users with little need for social engineering,[24] and the application could be infected by a cross-site scripting virus or worm.[25]The methods of injection can vary a great deal, and an attacker may not need to use the web application itself to exploit such a hole. Any data received by the web application (via email, system logs, etc) that can be controlled by an attacker must be encoded prior to re-display in a dynamic page, else an XSS vulnerability of this type could result.
  • Avoiding XSS requires action on the part of the user.[27][28] Defense against XSS falls also to content and web application developers, and to browser vendors. Users can usually disable scripting,[27] several best practices exist for content developers,[29] web applications can be tested and reviewed before release,[9] and some browsers today implement a few access-control policies.[30]Early policiesSeveral high profile security vulnerabilities followed the Netscape introduction in 1995 of the JavaScript language.[31] Netscape began to realize some of the security risks of allowing a Web server to send executable code to a browser (even if only in a browser sandbox). The company introduced the same origin policy in Netscape Navigator version 2.[32] One key problem is the case where users have more than one browser window (or tab, nowadays) open at once. In some instances, a script from one page should be allowed to access data from another page or object, but in others, this should be strictly forbidden because a malicious website could attempt to steal sensitive information. The policy forbids browsers to load a script when it crosses the boundary of the current Window object[33] unless the script originated from the same domain and over the same protocol and the same port if port is specified.[32] Essentially, this policy was intended to allow interaction between objects and pages but in theory a malicious Web site would not be able to access sensitive data in another browser window. Unfortunately browser vendors implemented the policy in different ways and the result was unpredictable behavior.[33] The policy also had loopholes, for example, an HTML element embedded in a page or resource at the origin host may link to a script hosted elsewhere and the browser will load that script when it loads the page.[33] Since then, other similar access-control policies have been adopted in other browsers and client-side scripting languages to protect end-users from malicious Web sites but the policies may depend on the user themself to guide access control according to their preferences. For example, digital signatures might identify scripts and their source to the user or user agent before a script can load.[30]Escaping and filteringOne way to eliminate some XSS vulnerabilities is to encode locally or at the server all user-supplied HTML special characters into character entities, thereby preventing them from being interpreted as HTML.[34] Unfortunately, users of many kinds of web applications (commonly forums and webmail) wish to use some of the features HTML provides. Some web applications such as social networking sites like MySpace and mainstream forum and blog software like WordPress and Movable Type attempt to identify malicious HTML constructs, and neutralize them, either by removing or encoding them.[35] But due to the flexibility and complexity of HTML and related standards, and the continuous addition of new features, it is almost impossible to know for sure if all possible injections are eliminated. Capabilities differ greatly among filtering systems and as of 2007 in Google's case were being written in house.[36] In order to eliminate certain injections, any server-side algorithm must either reject broken HTML, understand how every browser will interpret broken HTML,[37] or (preferably) fix the HTML to be well-formed using techniques akin to those of HTML Tidy.[38]Input validationInput validation for all potentially malicious data sources is another way to mitigate XSS. This is a common theme in application development (even outside of web development) and is generally very useful.[39] For instance, if a form accepts some field, which is supposed to contain a phone number, a server-side routine could remove all characters other than digits, parentheses, and dashes,[40] such that the result cannot contain a script. Input validation may help to mitigate other injection attacks such as SQL injection as well.[41] While effective for most types of input, there are times when an application, by design, must be able to accept special HTML characters, such as '<' and '>'.[41] In these situations, HTML entity encoding is the only option.[42]Cookie securityBesides content filtering, other methods for XSS mitigation are also commonly used. One example is that of cookie security. Many web applications rely on session cookies for authentication between individual HTTP requests, and because client-side scripts generally have access to these cookies, simple XSS exploits can steal these cookies.[34] To mitigate this particular threat (though not the XSS problem in general), many web applications tie session cookies to the IP address of the user who originally logged in, and only permit that IP to use that cookie.[43] This is effective in most situations (if an attacker is only after the cookie), but obviously breaks down in situations where an attacker is behind the same NATed IP address or web proxy.[43] IE (since version 6) and Firefox (since version 2.0.0.5) have an HttpOnly flag which allows a web server to set a cookie that is unavailable to client-side scripts but while beneficial, the feature does not prevent cookie theft nor can it prevent attacks within the browser.[44]Eliminating scriptsFinally, while Web 2.0 and Ajax designers favor the use of JavaScript,[45] some web applications are written to (sometimes optionally) operate completely without the need for client-side scripts.[46] This allows users, if they choose, to disable scripting in their browsers before using the application. In this way, even potentially malicious client-side scripts could be inserted unescaped on a page, and users would not be susceptible to XSS attacks.Many browsers can be configured to disable client-side scripts on a per-domain basis. If scripting is allowed by default, then this approach is of limited value, since it blocks bad sites only after the user knows that they are bad, which is too late. Functionality that blocks all scripting and external inclusions by default and then allows the user to enable it on a per-domain basis is more effective. This has been possible for a long time in IE (since version 4) by setting up its so called "Security Zones",[47] and in Opera (since version 9) using its "Site Specific Preferences".[48] A solution for Firefox and other Gecko-based browsers is the open source NoScript add-on which has anti-XSS protection.[49]The most significant problem with blocking all scripts on all websites by default is substantial reduction in functionality and responsiveness (client-side scripting can be much faster than server-side scripting because it does not need to connect to a remote server and the page or frame does not need to be reloaded[50]). Another problem with script blocking is that many users do not understand it, and do not know how to properly secure their browsers.[27] Another drawback is that most sites do not work without client-side scripting[dubious – discuss], forcing users to disable protection for that site and opening their systems to the threat.[51]
  • Vulnerabilities inside the database serverSometimes vulnerabilities can exist within the database server software itself, as was the case with the MySQL server's mysql_real_escape_string() function[1]. This would allow an attacker to perform a successful SQL injection attack based on bad Unicode characters even if the user's input is being escaped.Blind SQL InjectionBlind SQL Injection is used when a web application is vulnerable to SQL injection but the results of the injection are not visible to the attacker. The page with the vulnerability may not be one that displays data but will display differently depending on the results of a logical statement injected into the legitimate SQL statement called for that page. This type of attack can become time-intensive because a new statement must be crafted for each bit recovered. There are several tools that can automate these attacks once the location of the vulnerability and the target information has been established.[2]Conditional ResponsesOne type of blind SQL injection forces the database to evaluate a logical statement on an ordinary application screen.SELECT booktitle FROM booklist WHERE bookId = 'OOk14cd' AND 1=1 will result in a normal page whileSELECT booktitle FROM booklist WHERE bookId = 'OOk14cd' AND 1=2 will likely give a different result if the page is vulnerable to a SQL injection. An injection like this will prove that a blind SQL injection is possible, leaving the attacker to devise statements that evaluate to true or false depending on the contents of a field in another table.[3]Conditional ErrorsThis type of blind SQL injection causes a SQL error by forcing the database to evaluate a statement that causes an error if the WHERE statement is true. For example,SELECT 1/0 FROM users WHERE username='Ralph' the division by zero will only be evaluated and result in an error if user Ralph exists.Time DelaysTime Delays are a type of blind SQL injection that cause the SQL engine to execute a long running query or a time delay statement depending on the logic injected. The attacker can then measure the time the page takes to load to determine if the injected statement is true.
  • Incorrectly filtered escape charactersThis form of SQL injection occurs when user input is not filtered for escape characters and is then passed into a SQL statement. This results in the potential manipulation of the statements performed on the database by the end user of the application.The following line of code illustrates this vulnerability:statement = "SELECT * FROM users WHERE name = '" + userName + "';" This SQL code is designed to pull up the records of a specified username from its table of users. However, if the "userName" variable is crafted in a specific way by a malicious user, the SQL statement may do more than the code author intended. For example, setting the "userName" variable asa' or 't'='t renders this SQL statement by the parent language:SELECT * FROM users WHERE name = 'a' OR 't'='t'; If this code were to be used in an authentication procedure then this example could be used to force the selection of a valid username because the evaluation of 't'='t' is always true.While most SQL Server implementations allow multiple statements to be executed with one call, some SQL APIs such as php's mysql_query do not allow this for security reasons. This prevents hackers from injecting entirely separate queries, but doesn't stop them from modifying queries. The following value of "userName" in the statement below would cause the deletion of the "users" table as well as the selection of all data from the "data" table (in essence revealing the information of every user):a';DROP TABLE users; SELECT * FROM data WHERE name LIKE '% This input renders the final SQL statement as follows:SELECT * FROM Users WHERE name = 'a';DROP TABLE users; SELECT * FROM DATA WHERE name LIKE '%';Incorrect type handlingThis form of SQL injection occurs when a user supplied field is not strongly typed or is not checked for type constraints. This could take place when a numeric field is to be used in a SQL statement, but the programmer makes no checks to validate that the user supplied input is numeric. For example:statement := "SELECT * FROM data WHERE id = " + a_variable + ";" It is clear from this statement that the author intended a_variable to be a number correlating to the "id" field. However, if it is in fact a string then the end user may manipulate the statement as they choose, thereby bypassing the need for escape characters. For example, setting a_variable to1;DROP TABLE users will drop (delete) the "users" table from the database, since the SQL would be rendered as follows:SELECT * FROM DATA WHERE id=1;DROP TABLE users;
  • To protect against SQL injection, user input must not directly be embedded in SQL statements. Instead, user input must be escaped or filtered or parameterized statements must be used.Using EscapingA straight-forward, though error-prone way to prevent injections is to escape dangerous characters. For instance, every occurence of a single quote (') in a parameter must be replaced by two single quotes ('') to form a valid SQL string literal. In PHP, for example, it is usual to escape parameters using the function mysql_real_escape_string before sending the SQL query:$query = sprintf("SELECT * FROM Users where UserName='%s' and Password='%s'", mysql_real_escape_string($Username), mysql_real_escape_string($Password));mysql_query($query);However, escaping is error-prone as it relies on the programmer to escape every parameter. Also, if the escape function fails to handle a special character correctly, an injection is still possible.Using Stored ProceduresStored Procedures add an extra layer of abstraction in to the design of a software system. This means that, so long as the interface on the stored procedure stays the same, the underlying table structure can change with no noticeable consequence to the application that is using the database. This layer of abstraction also helps put up an extra barrier to potential attackers. If access to the data in SQL Server is only ever permitted via stored procedures, then permission does not need to be explicitly set on any of the tables. Therefore, none of the tables should ever need to be exposed directly to outside applications. For an outside application to read or modify the database, it must go through stored procedures. Even though some stored procedures, if used incorrectly, could potentially damage the database, anything that can reduce the attack surface is beneficial.Stored procedures can be written to validate any input that is sent to them to ensure the integrity of the data beyond the simple constraints otherwise available on the tables. Parameters can be checked for valid ranges. Information can be cross checked with data in other tables.Using Parameterized StatementsIn some programming languages such as Java and .NET parameterized statements can be used that work with parameters (sometimes called placeholders or bind variables) instead of embedding user input in the statement. In many cases, the SQL statement is fixed. The user input is then assigned (bound) to a parameter. This is an example using Java and the JDBC API:PreparedStatement prep = conn.prepareStatement("SELECT * FROM USERS WHERE USERNAME=? AND PASSWORD=?");prep.setString(1, username);prep.setString(2, password);Similarly, in C#:using (SqlCommandmyCommand = new SqlCommand("SELECT * FROM USERS WHERE USERNAME=@username AND PASSWORD=HASHBYTES('SHA1', @password)", myConnection)) { myCommand.Parameters.AddWithValue("@username", user);myCommand.Parameters.AddWithValue("@password", pass);myConnection.Open();SqlDataReadermyReader = myCommand.ExecuteReader()) ................... }In PHP version 5 and MySQL version 4.1 and above, it is possible to use prepared statements through vendor-specific extensions like mysqli[4]. Example[5]:$db = new mysqli("localhost", "user", "pass", "database");$stmt = $db -> prepare("SELECT priv FROM testUsers WHERE username=? AND password=?");$stmt -> bind_param("ss", $user, $pass);$stmt -> execute();In ColdFusion, the CFQUERYPARAM statement is useful in conjunction with the CFQUERY statement to nullify the effect of SQL code passed within the CFQUERYPARAM value as part of the SQL clause.[6] [7]. An example is below.<cfquery name="Recordset1" datasource="cafetownsend">SELECT *FROM COMMENTSWHERE COMMENT_ID =<cfqueryparam value="#URL.COMMENT_ID#" cfsqltype="cf_sql_numeric"></cfquery>Enforcing the Use of Parameterized StatementsThere are two ways to ensure an application is not vulnerable to SQL injection: using code reviews (which is a manual process), and enforcing the use of parameterized statements. Enforcing the use of parameterized statements means that SQL statements with embedded user input are rejected at runtime. Currently only the H2 Database Engine supports this feature.
  • The impact of these weaknesses can be devastating to the security of a website. Encryption is generally used to protect a site’s most sensitive assets, which may be totally compromised by a weakness. #1: Security by ObscurityOne of the basic security principles that every software developer / designer should follow when writing secure applicationsIn the crypto context, usually related to:Hiding the Crypto algorithms / protocols being usedHiding the Crypto keys generation algorithmsHiding the Crypto keysHiding initialization parametersSimply does not work … Once revealed, usually results in total breakdown of the system security modelSide effect is the prevention of “other-eyes” from inspecting / reviewing the algorithms being used for potential weaknesses that can be fixed#2: Using Traditional Crypto“Traditional” or “Classical” Cryptography covers algorithms and techniques used to perform cryptographic operations in the “old-days”Popular examples include:Shift Cipher (e.g. Caesar / C3)Substitution CipherAffine CipherVigenere CipherEffective Cryptanalysis techniques / tools are considered common knowledge and usually result in the total breakdown of these algorithms#3: Using Proprietary CryptoIncludes the modification of standard crypto algorithms or the usage of proprietary new crypto algorithmsUsually combined with #1 (Security by Obscurity)In most cases standard algorithms / methods cover most aspects needed by software developersUnless you have vast experience and significant resources to invest in the cryptanalysis research of the new algorithm – usually results in poor algorithm that can be easily broken#4: Using Insecure Random GeneratorsUsually Random Generators are not truly random but rather Pseudo Random algorithmsCommon usage of the random generators in the crypto context usually includes a generation of:One-time-passwordsAccess codesCrypto keysSession identifiersSome of the generators were planned to support statistical requirements (e.g. uniformly distribution) and not to provide secure unpredictable valuesSome of the generators are required to be initialized by using SEED value. Usage of the same SEED provides the same sequence – causing the choosing of the SEED to be critical for securityUsing random generators that are considered insecure or the insecure initialization of these generators usually results in the ability of an attacker in predict other values that were generated by the random generator#5: ‘Hiding’ SecretsSecure systems need to handle secrets These secrets are usually access credentials to other systems (e.g. DBMS) or crypto keys (sometimes even to protect those access credentials)In many cases, to protect those secrets developers ‘hides’ them in several places suchas:Application source codeConfiguration filesWindows RegistryIt is common belief that since application code is ‘compiled’ into binary executable it would be hard to extract them The fact is that extracting those secrets from application ‘compiled’ code is eventually not as hard as it seems and can be done using various tools and techniquesSome programming languages (e.g. Java, .NET) do not produce ‘true’ binary making the extraction job even easierAdditional problems with ‘hard-coded’ secrets are that they are hard to maintain and expose these secrets to developers or to less secure environments (e.g. Testing, Integration, Source Control)As for hiding the secrets in external resources (e.g. files), plenty of available tools can be easily used to discover the resource used for storage and easily recover the secret#6: Using Weak KeysSystems that use crypto must use crypto keys to perform various crypto activities (e.g. for encryption, decryption, MAC)These crypto keys are sometime based on chosen passwords that might seem long & hard but when used as keys are weakOther cases include key generation using an insecure generator (e.g. pseudo random generator or other ‘obscured’ techniques)The strength of the entire crypto scheme is heavily dependent upon keys’ strength It is important to notice that strength is not always equal to lengthExample: 8 char alpha numeric passwords strength is not equal to 64- bit crypto key but rather to 40-bit crypto key!Secure crypto schemes (e.g. AES, RSA) are almost useless and can be easily defeated when used with weak keys#7: Memory ProtectionIn most cases sensitive crypto data is stored in the host’s memoryMost of the time this information is stored unprotected (without any Encryption)Many times this information is stored for a longer period than actually needed (enlarging the attack window)Many times the memory is not specifically overwritten to perform the actual removal of the sensitive information from memoryIn some programming languages the information is even stored (usually due to insufficient knowledge) within a mutable object preventing it from being specifically erased …Insufficient memory protection jeopardizes the sensitive information (usually crypto Keys) to be ‘leaked’ out to an unauthorized attacker causing direct risk to the entire cryptosystem#8: Not Using ‘Salted’ HashCrypto Hash Functions are sometimes used to store ‘one-way’ version of Passwords (or other credentials that needs to be authenticated)Popular implementation includes a simple replacement of the Password field with the ‘Hashed’ version and the performance of the checks against itNot using any ‘Salt’ on the stored Hash Values exposes this scheme to Dictionary Attack that can totally break this scheme!#9: Using MAC InsecurelyMAC is used to secure the integrity of the message and to authenticate the sender by using a Shared SecretPopular MAC implementations are based on un-keyed Hashes operated on the data combined with the Shared SecretThe Data + Shared Secret ‘combination’ is usually the concatenation operationDue to its mathematical operation of the iterative Hash function, if not carefully built, data can be altered and a matching MAC can be calculated without knowing the Shared Secret!#10: Insecure Initialization – ExampleUsage of Shared Modulus in RSA results in total breakdown of the entire cryptosystem
  • The impact of these weaknesses can be devastating to the security of a website. Encryption is generally used to protect a site’s most sensitive assets, which may be totally compromised by a weakness. #1: Security by ObscurityOne of the basic security principles that every software developer / designer should follow when writing secure applicationsIn the crypto context, usually related to:Hiding the Crypto algorithms / protocols being usedHiding the Crypto keys generation algorithmsHiding the Crypto keysHiding initialization parametersSimply does not work … Once revealed, usually results in total breakdown of the system security modelSide effect is the prevention of “other-eyes” from inspecting / reviewing the algorithms being used for potential weaknesses that can be fixed#2: Using Traditional Crypto“Traditional” or “Classical” Cryptography covers algorithms and techniques used to perform cryptographic operations in the “old-days”Popular examples include:Shift Cipher (e.g. Caesar / C3)Substitution CipherAffine CipherVigenere CipherEffective Cryptanalysis techniques / tools are considered common knowledge and usually result in the total breakdown of these algorithms#4: Using Insecure Random GeneratorsUsually Random Generators are not truly random but rather Pseudo Random algorithmsCommon usage of the random generators in the crypto context usually includes a generation of:One-time-passwordsAccess codesCrypto keysSession identifiersSome of the generators were planned to support statistical requirements (e.g. uniformly distribution) and not to provide secure unpredictable valuesSome of the generators are required to be initialized by using SEED value. Usage of the same SEED provides the same sequence – causing the choosing of the SEED to be critical for securityUsing random generators that are considered insecure or the insecure initialization of these generators usually results in the ability of an attacker in predict other values that were generated by the random generator#5: ‘Hiding’ SecretsSecure systems need to handle secrets These secrets are usually access credentials to other systems (e.g. DBMS) or crypto keys (sometimes even to protect those access credentials)In many cases, to protect those secrets developers ‘hides’ them in several places suchas:Application source codeConfiguration filesWindows RegistryIt is common belief that since application code is ‘compiled’ into binary executable it would be hard to extract them The fact is that extracting those secrets from application ‘compiled’ code is eventually not as hard as it seems and can be done using various tools and techniquesSome programming languages (e.g. Java, .NET) do not produce ‘true’ binary making the extraction job even easierAdditional problems with ‘hard-coded’ secrets are that they are hard to maintain and expose these secrets to developers or to less secure environments (e.g. Testing, Integration, Source Control)As for hiding the secrets in external resources (e.g. files), plenty of available tools can be easily used to discover the resource used for storage and easily recover the secret#6: Using Weak KeysSystems that use crypto must use crypto keys to perform various crypto activities (e.g. for encryption, decryption, MAC)These crypto keys are sometime based on chosen passwords that might seem long & hard but when used as keys are weakOther cases include key generation using an insecure generator (e.g. pseudo random generator or other ‘obscured’ techniques)The strength of the entire crypto scheme is heavily dependent upon keys’ strength It is important to notice that strength is not always equal to lengthExample: 8 char alpha numeric passwords strength is not equal to 64- bit crypto key but rather to 40-bit crypto key!Secure crypto schemes (e.g. AES, RSA) are almost useless and can be easily defeated when used with weak keys#7: Memory ProtectionIn most cases sensitive crypto data is stored in the host’s memoryMost of the time this information is stored unprotected (without any Encryption)Many times this information is stored for a longer period than actually needed (enlarging the attack window)Many times the memory is not specifically overwritten to perform the actual removal of the sensitive information from memoryIn some programming languages the information is even stored (usually due to insufficient knowledge) within a mutable object preventing it from being specifically erased …Insufficient memory protection jeopardizes the sensitive information (usually crypto Keys) to be ‘leaked’ out to an unauthorized attacker causing direct risk to the entire cryptosystem#8: Not Using ‘Salted’ HashCrypto Hash Functions are sometimes used to store ‘one-way’ version of Passwords (or other credentials that needs to be authenticated)Popular implementation includes a simple replacement of the Password field with the ‘Hashed’ version and the performance of the checks against itNot using any ‘Salt’ on the stored Hash Values exposes this scheme to Dictionary Attack that can totally break this scheme!#9: Using MAC InsecurelyMAC is used to secure the integrity of the message and to authenticate the sender by using a Shared SecretPopular MAC implementations are based on un-keyed Hashes operated on the data combined with the Shared SecretThe Data + Shared Secret ‘combination’ is usually the concatenation operationDue to its mathematical operation of the iterative Hash function, if not carefully built, data can be altered and a matching MAC can be calculated without knowing the Shared Secret!#10: Insecure Initialization – ExampleUsage of Shared Modulus in RSA results in total breakdown of the entire cryptosystem
  • How to choose the right algorithm You choose an algorithm based on your scenario and requirement. For example, if you require data confidentiality use an encryption algorithm. If you require data integrity use a hash-based message authentication code or a digital signature. You use hashing when you want to avoid storing a password and instead compare the hash value with a recalculated hash obtained from the user supplied password.  Symmetric and asymmetric encryption are often used together. A symmetric encryption key is used as a session key to encrypt message data, and asymmetric encryption is used to encrypt the symmetric key and initialization vector prior to exchanging these values between two parties. Classes in the System.Security.Cryptography namespace provide support for symmetric encryption, asymmetric encryption, hashing, generating random numbers, and creating digital signatures. Use the following guidelines when you select a cryptographic algorithm: Symmetric encryption. Use these to encrypt large streams of data. Use Rijndael (now referred to as Advanced Encryption Standard [AES]) or Triple Data Encryption Standard (3DES).Asymmetric or public/private key encryption. The .NET Framework provides managed classes for Rivest, Shamir, Adleman (RSA), and Digital Signature Algorithm (DSA) asymmetric encryption. DSA can be used for digital signatures only. If interoperability is an issue, you need to find out what algorithms the other party you are interoperating with supports, and use those. If you are interested in both signing and encryption, select RSA. If you are concerned about performance, you should be aware that DSA is faster at key generation and RSA is faster at signature generation. Measure the performance of both approaches in your scenario.Hashing. Use a hashing algorithm such as SHA256 when you need a principal to prove it knows a secret that it shares with you. The main drawback with using hashes for passwords is that they do not allow you to retrieve the password later, if needed. Use HMACSHA256 with Message Authentication Codes (MAC), which require you and the client to share a key. This can provide integrity checking and a degree of authentication.How to choose the appropriate key size When generating an encryption key or key pair, use the largest key size that the algorithm supports. This does not necessarily make the algorithm more secure, but it dramatically increases the time needed to successfully perform a brute force attack on the key.How to generate a random number If you need to generate encryption keys programmatically, use the RNGCryptoServiceProvider class to create keys and initialization vectors and do not use the Random class. Unlike the Random class, RNGCryptoServiceProvider creates cryptographically strong random numbers that are FIPS-140 compliant. How to manage keys and other sensitive data To avoid key management, consider using DPAPI encryption where possible. With DPAPI, the operating system manages the key. For example, a good use for DPAPI is to encrypt symmetric encryption keys used to encrypt data in a database. Cycle keys periodically. Change your encryption keys regularly because a static secret is more likely to be discovered over time. Do not overuse keys. Protect exported private keys. Use the PasswordDeriveBytes class when you export an RSA or DSA private key. The RSA and DSA classes contain a ToXmlString method, which enables you to export the public key or private key (or both) from the key container. This method exports the private key in plain text. If you export the private key to be installed on multiple servers in a Web farm, you should encrypt the key after exporting the private key by using PasswordDeriveBytes to generate a symmetric keyHow to use hashing Use a hashing algorithm, such as SHA256, SHA1 or MD5, when you need a principal to prove it knows a secret that it shares with you. You can use SHA256 on the .NET Framework version 2.0 because it provides a managed implementation of SHA256. For .NET Framework version 1.1, you should use SHA1 and not MD5 because it generates a 160-bit hash output, while MD5 generates a 128-bit output.How to implement an integrity check You can use integrity checking to verify that data sent via an unsecured communication channel has not been modified. You can implement integrity checks on your data with a data hash or a digital signature. A data hash alone does not ensure integrity because both the data and the hash could be modified by a malicious user. Use a digital signature or the System.Security.Cryptography.HMACSHA1 hashing class to help ensure data integrity. An integrity check is performed by verifying that the hash value of the received data matches the hash value of the data that was sent. The Hash-based Message Authentication Code (HMAC) verifies that both the hashed data and the hash itself have not been altered. When you perform an integrity check with an HMAC, follow these guidelines: The sender and receiver must both have knowledge of a private key that will be used to calculate the HMAC.Generate an HMAC from the data by using the HMACSHA1 class.Send the data and the HMAC to the recipient.Verify the integrity of received data by computing an HMAC on the data and comparing it to the HMAC sent. If the private key has not been stolen and the HMAC values match, you can be sure that the data has not been modified.How to use a digital certificate Use the System.Security.Cryptography.X509Certificates namespace to access digital certificates. You can load a certificate from a file or select one from a physical store. Use the X509Certificate2 class to load a certificate from a file, and use the X509Store class to load a certificate from a store. You can use certificates with the SslStream class to authenticate the server or the client during an SSL transaction. Use the SslStream.AutheticateAsServer or SslStream.AutheticateAsClient enumerations to complete the authentication process. How to use passwords to generate keys In .NET version 1.1 you could use PasswordDeriveBytes to generate keys from a password. NET version 2.0 still supports this for backward compatibility but you should now use Rfc2898DeriveBytes. The main advantage is that it supports the RSA Password-Based Key Derivation Function version 2 (PBKDF2), which is an improved version of the PBKDF1 standard implementation used by PasswordDeriveBytes. To use Rfc2898DeriveBytes, supply at minimum a password and salt value. You can also specify a number of iterations to derive the key if you want to override the default 1000 iterations. Rfc2898DeriveBytes uses HMACSHA1 as an underlying pseudo-random generator. After the key is used to encrypt the data, clear it from memory but persist the salt and the number of iterations if you changed the default value. These values should be protected and are needed to regenerate the key for decryption.
  • Don't Grow Your Own CryptoUnless you are a crypto mathematician and your job is to build crypto algorithmsThere are many ways to get it wrong...New algorithms require years of analysis by many experts to be verified and acceptedProprietary algorithms won't get the level scrutiny that open algorithms willJust because you can't break it, doesn't mean that someone else can't break itDon't Assume Too MuchThat'll never happen...” (epidemic)Plan on multiple protection mechanisms failing or being bypassed rather than assuming they'll just work“Don't underestimate the power of the dark side...”Software disassembly techniques and tools are getting better all the timeIf your secrets are important enough, someone will attempt to get themDon't Rely On ObfuscationIt's very difficult to prevent algorithm recovery when the attacker has full access to the client software, device, or whatever...Your time is better spent hardening server-side components and placing zero trust in client-side components that are out of your controlAssume that any obfuscation you use is transparentDon't hide keys where they can be recovered – even if you think they can't be recoveredUse Care When Implementing CryptoKnow how and why you are using itUse standard libraries that have already worked out most of the kinksUse previously stated guiding principlesDon't grow your own cryptoDon't assume too muchDon't rely on obfuscationDesign from your data outDesign for agility
  • Security Training: #4 Development: Typical Security Issues

    1. 1. Development: Typical Security Issues Overview Yuri Voynalovich, Oleh Melnik, Oleg Basarab, Yulian Slobodian November 2008
    2. 2. Presentation Plan  Introduction  Buffer Overrun (Overflow)  Integer arithmetic errors  Cross-site scripting  SQL injection  Crypto Pitfalls 2
    3. 3. Introduction
    4. 4. Top Misunderstandings of Information Security  I thought the firewall would take care of this. Or file permissions. Or SSL.  I’m an experienced web developer and don’t think I need this.  Can’t someone do this after I finish my dev work?  It's encrypted, so it's secure.  No one knows my algorithm, so it must be secure.  Once a piece of code is deemed secure in one system, is secure for use everywhere.  But that's the way we've always done it. 4
    5. 5. The Need for Secure Systems  A secure product: a product that protects the confidentiality, integrity, and availability of the customers' information, and the integrity and availability of processing resources, under control of the system's owner or administrator.  A security vulnerability: a flaw in a product that makes it infeasible—even when using the product properly—to prevent an attacker from usurping privileges on the user's system, regulating its operation, compromising data on it, or assuming ungranted trust. Information security Availability Integrity Confidentiality Source: Microsoft.com 5
    6. 6. Buffer overruns
    7. 7. Buffer Overrun Types  Stack Overruns  Heap Overruns  Array Indexing Errors  Format String Bugs 7
    8. 8. Simple buffer overrun example  The buffer overrun caused by Unicode and ANSI buffer size mismatches is somewhat common on Windows platforms, it occurs if you mix up the number of elements with the size in bytes of a Unicode buffer  The most commonly used function that is vulnerable to this kind of bug is MultiByteToWideChar: Vulnerable code: BOOL GetName(char *szName) { WCHAR wszUserName[256]; // Convert ANSI name to Unicode. MultiByteToWideChar(CP_ACP, 0, szName, -1, wszUserName, sizeof(wszUserName)); // Snip } Correct way to write this function: MultiByteToWideChar(CP_ACP, 0, szName, -1, wszUserName, sizeof(wszUserName) / sizeof(wszUserName[0])); 8
    9. 9. Preventing Buffer Overruns  The first line of defense is simply to write solid code!  Always validate all your inputs  Use safe functions  Use Standard Template Library or other safe libraries  Use stack-smashing protection  Use pointer protection  Use executable space protection  Use address space layout randomization  Use deep packet inspection  Stacks that grow up  Stack canaries  No executable stack 9
    10. 10. Integer overflows
    11. 11. Integer Overflow Types  Overflow  Underflow  Signedness Error  Truncation 11
    12. 12. Integer Overflow Example Vulnerable code: char* processNext(char* strm) { char buf[512]; short len = *(short*) strm; strm += sizeof(len); } if (len <= 512) { memcpy(buf, strm, len); process(buf); return strm + len; } else { return -1; } 12
    13. 13. Typical Integer exploits  Arbitrary code execution  Denial of Service (DoS) attacks  Array index attacks  Bypassing sanitization attacks  Logic errors 13
    14. 14. Preventing Integer Errors  Range Checking  Strong Typing  Compiler-Generated Runtime Checks  Safe Integer Operations  Arbitrary Precision Arithmetic  Source Code Audit 14
    15. 15. Cross-site scripting
    16. 16. XSS Types  DOM-based  Non-Persistent  Persistent 16
    17. 17. Cross-Site Scripting Illustrated Example Attacker sets the trap – update my profile Victim views page – sees attacker profile Communication Knowledge Mgmt E-Commerce Bus. Functions 2 Application with stored XSS vulnerability Administration Transactions Attacker enters a malicious script into a web page that stores the data on the server Accounts Finance 1 Custom Code Script runs inside victim’s browser with full access to the DOM and cookies 3 Script silently sends attacker Victim’s session cookie 17
    18. 18. Typical XSS Results  Identity theft  Accessing sensitive or restricted information  Gaining free access to otherwise paid for content  Spying on user’s web browsing habits  Altering browser functionality  Public defamation of an individual or corporation  Web application defacement  Denial of Service attacks 18
    19. 19. Preventing XSS  Early policies  Escaping and filtering  Input validation  Cookie security  Eliminating scripts 19
    20. 20. SQL Injection
    21. 21. Forms of SQL Injection  Incorrectly filtered escape characters  Incorrect type handling  Vulnerabilities inside the database server  Blind SQL Injection  Conditional Responses  Conditional Errors  Time Delays 21
    22. 22. SQL Injection Examples  Incorrectly filtered escape characters statement = "SELECT * FROM users WHERE name = '" + userName + "';" UserName  a' or 't'='t SELECT * FROM users WHERE name = 'a' OR 't'='t'; userName  a';DROP TABLE users; SELECT * FROM data WHERE name LIKE '% SELECT * FROM Users WHERE name = 'a';DROP TABLE users; SELECT * FROM DATA WHERE name LIKE '%';  Incorrect type handling statement := "SELECT * FROM data WHERE id = " + a_variable + ";― a_variable  1;DROP TABLE users SELECT * FROM DATA WHERE id=1;DROP TABLE users; 22
    23. 23. Preventing SQL Injection  Using Escaping  Access the database using an account with the least privileges necessary  Using Parameterized Statements  Using Stored Procedures  Re-validate data in stored procedures  Enforcing the Use of Parameterized Statements 23
    24. 24. Crypto Pitfalls
    25. 25. The “Top 10” List of Crypto Pitfalls  Security by Obscurity  Using Traditional Cryptography  Using Proprietary Cryptography  Using Insecure Random Generators  ‘Hiding’ Secrets  Using Weak Keys  Memory Protection  Not Using ‘Salted’ Hash  Using MAC Insecurely  Insecure Initialization 25
    26. 26. Home Grown Encryption  Bad idea to invent encryption algorithms  Do not accept proprietary encryption  Acceptable algorithms are very difficult and require:  Invented by professional cryptologist  Subject to years of open analysis and scrutiny  Many past failures by the brightest and well funded  MD4 hash by Ronald Rivest  Helix by Bruce Schneier  LANMAN Hash by Microsoft  DVD CSS (Content Scrambling System) 26
    27. 27. How to: avoid Weak Cryptography  Choose the right algorithm  Choose the appropriate key size  Generate a random number  Manage keys and other sensitive data  Use hashing  Implement an integrity check  Use a digital certificate  Use passwords to generate keys 27
    28. 28. Conclusions  Know what you are doing  Do not rely on ‘Obscurity’  Do not try to ‘Hide’ secrets  Do not re-invent the wheel  Generate Strong Keys and Protect them  Use only strong & standard Ciphersuites  Don't Grow Your Own Crypto  Don't Assume Too Much  Use Care When Implementing Crypto 28
    29. 29. References  http://download.microsoft.com/download/d/9/a/d9abfa8d-2207-4827-9e15d0375b288495/Writing%20Secure%20Code%20--%20Best%20Practices.ppt  http://www.arcert.gov.ar/webs/textos/best_prac_for_sec_dev4.pdf  http://blogs.msdn.com/michael_howard/archive/2006/02/02/523392.aspx  http://doc.bughunter.net/buffer-overflow/heap-corruption.html  http://en.wikipedia.org/wiki/Buffer_overflow  http://en.wikipedia.org/wiki/Code_review  http://en.wikipedia.org/wiki/Cross-site_scripting  http://en.wikipedia.org/wiki/Cryptography  http://en.wikipedia.org/wiki/SQL_injection  http://java.sun.com/security/seccodeguide.html  http://msdn.microsoft.com/en-us/library/aa480479.aspx#pagpractices0002_cryptography  http://msdn.microsoft.com/en-us/library/aa720329(VS.71).aspx  http://msdn.microsoft.com/en-us/library/bb892733.aspx  http://msdn.microsoft.com/en-us/library/ms998364.aspx  http://msdn.microsoft.com/en-us/magazine/cc163518.aspx  http://www.cs.virginia.edu/~nrp3d/papers/computers_and_security-net-java.pdf 29
    30. 30. References  http://my.safaribooksonline.com/0735617228/IDA0TYR  http://my.safaribooksonline.com/0735617228/IDALQET  http://smartbear.com/docs/BestPracticesForPeerCodeReview.pdf  http://www.cs.cmu.edu/~dbrumley/pubs/integer-ndss-07.pdf  http://www.darkreading.com/security/app-security/showArticle.jhtml?articleID=208804113  http://www.gotdotnet.ru/LearnDotNet/NETFramework/661.aspx  http://www.heise-online.co.uk/security/A-Heap-of-Risk--/features/74634/6  http://www.informit.com/content/images/0321335724/samplechapter/seacord_ch05.pdf  http://www.it-eye.nl/weblog/2007/06/13/soa-best-practice-9-use-a-canonical-data-model/  http://www.onjava.com/pub/a/onjava/excerpt/weblogic_chap17/index.html?page=1  http://www.safecode.org/publications/SAFECode_Dev_Practices1008.pdf  http://www.schneier.com/essay-155.html  http://www.securitylab.ru/analytics/216249.php  http://www.securitylab.ru/analytics/350799.php  http://www.tech-faq.com/integer-overflow.shtml  http://www3.interscience.wiley.com/journal/94515736/abstract?CRETRY=1&SRETRY=0  https://buildsecurityin.us-cert.gov/daisy/bsi/articles/knowledge/coding/312-BSI.html 30

    ×