And, for that reason TypeScript needs a security champion.
Typed Language Types
TypeScript is a strongly typed language. Languages can generally be divided between strongly and weakly typed. Strongly typed languages require explicit declarations to convert or compare between types. Weakly typed languages, on the other hand, allow comparison and conversion between types without any explicit declarations. Strong languages are better and more secure because they require that extra step in order to convert between languages. They won’t allow you to change a character into a number unless you force it to, this allows for the mitigation of errors and weaknesses such as the CWE-704 Incorrect Type Conversion or Cast.
TypeScript is also a statically typed language. Whether a language is considered static or dynamic is based on when types are checked within the language. A statically typed language will check types at compile time and a dynamically typed language will check types at runtime. Statically typed languages are more secure because they can find any potential type errors before they are propagated into the program while they are not yet exposed as exploitable vulnerabilities in a production application.
TypeScript Wins Security
Across the Internet, there is plenty of dislike for TypeScript. Here’s how security wins against the eleven popular reasons developers disapprove of TypeScript.
1. TypeScript increases project compilation time from 1 second to 3-4 seconds.
TypeScript Security Win: The compiler finds errors during compile time, preventing them from propagating to runtime.
2. TypeScript requires a minimum of 30% more code.
While more code is written, you are generating more code to increase security. The extra code defines types and adds type checks and validation functions. Types define what input is allowed into an object; not having types can cause errors and potential security weaknesses. In TypeScript, the types are strings, numbers, and interfaces, which can help define the syntax of future type checks and input validation. Writing extra code upfront to define types and ensure type safety can help save time by preventing developers from having to fix type errors later.
Fixing type errors in languages without static, strict types is difficult - you have to figure out where in the code the error is generating from, how to fix it, and determine if any other errors resulted from the fix, all without the help of the IDE or the language itself. While in a strict static typed language, it will prevent these issues entirely and report any additional errors during compilation.
TypeScript Security Win: Types provide a controlled way to define the input you expect for a particular variable or data structure.
3. Dynamic Typing is not a problem.
In fact, dynamic Typing is a security problem, because it only checks types at runtime. Therefore, any security issues are caught while the application is running and not while it is under development. Static typing checks types at compile-time, which prevents type issues before they become vulnerabilities. When you are trying to remediate the source of an error or weakness, it takes longer to edit code in dynamic typing than in static typing. This is due to the expressive errors and compile-time type checks native to static typing. More expressive errors give more information about where the code's errors lie, such as the file and line number. Checking types at compile time means that errors are found closer to the source, making it easier to return and fix than if the error was found during runtime.
TypeScript Security Win: TypeScript provides static typing, which checks types at compile-time, preventing issues before they become vulnerabilities, and giving more expressive errors to aid in the identification and resolution of errors.
4. There is no NEED for types/strict typing.
Types and strict typing are necessary for security purposes. Strict types prevent the reassignment or comparison of types without explicit declarations. It will not let you take the variable x and redefine it from a number to a string. It will not let you take the string variable y and store it into the number variable x, not without an explicit declaration to overrule the language. There are multiple CWE's that can only be corrected and prevented using strict types.
Taking in incorrect types, incorrect type conversions, and certain other weaknesses are best prevented using strict typing. If strict typing does not exist within a language, then it does not care if a string is entered into a number variable or if a string is transformed into a number. It's not going to give you any warnings or help; the language assumes you know what you're doing. Maybe you think that's a benefit, but it is an extremely unnecessary risk. One developer may love weak typing because they always know what they're doing and never make typing mistakes. But very rarely is an application going to only have one developer, and typing issues very easily slip through the cracks. Why rely on people to catch everything when your language can help?
TypeScript Security Win: TypeScript uses strict typing, preventing accidental typing mistakes that lead to common weaknesses within an application.
5. TypeScript prevented my API from sending an object without all the suitable properties.
When TypeScript prevents an object from entering the system when it is not of the right type or syntax, TypeScript is doing its job. It’s always safer to validate that the input has all of the correct properties than to allow objects with missing properties into the system. While not being able to send incomplete objects might be annoying, it is always better to know what the object contains and be assured nothing is missing or extra. While TypeScript does allow extra properties in objects due to duck typing, you can use nominal typing instead by using brands in objects. You want to validate all input and not allow any objects that don't contain the correct properties or types into the system.
TypeScript Security Win: TypeScript forces a level of input validation inherently within types.
TypeScript SeCurity Win: The time spent learning TypeScript is worth the investment for a security return.
7. TypeScript removes all of my creativity as a developer, forcing the manual typing of everything.
The TypeScript compiler infers types for variables that are initialized. Only uninitialized variables require manual typing. Don’t assume that the compiler will always consider the correct type for a variable; this is how you get type errors within code.
An example of a type error is when a function accepts only numbers, but it is called with strings. Don’t place creativity above security. Creativity is important; however, customers will not care how creative your code is if it is not also keeping their information safe. You shouldn't care how creative or pretty your code is if it is insecure and breaks every time a username is submitted as input, because the compiler guesses that it was supposed to be a number. There is also an argument to be made that if you cannot figure out how to accomplish your goals while staying within the confines of security then you are not truly trying to be creative, you are just playing around.
TypeScript Security Win: TypeScript encourages creativity, pushing you to accomplish your goals while also staying secure.
8. It is risky to rely on the compiler to check types rather than doing it yourself.
There is risk in both options, relying on the compiler to check the correct usage of the number type or doing it yourself. If you must choose one over the other, rely on the compiler over your own abilities. Assuming you are working with other developers, do not rely on every single developer to avoid type checking mistakes. Another issue in checking all types yourself is that there becomes a point where it is no longer feasible. There becomes a point in which the application is so large that it is no longer possible to check all types manually.
Compilers do not have the same understanding as people and may miss certain things when checking types, or alternatively flag types as wrong when they are correct. However, the compiler will catch more issues and have greater consistency than any individual developer. Redundancy is the best avenue in this instance. A developer should always check types and add tests within the code. The compiler can be used to find additional issues the developer may have missed.
TypeScript Security Win: Check types as you write the code and then use the compiler to catch any type issues you may have missed.
9. There is no point in having both type definitions and maintaining types at runtime.
Actually, there is a massive benefit in having both type definitions and ensuring the types are maintained at runtime. Checking at both compile and runtime means that there are two different points in which types are checked. This is enforcing a level of redundancy; there will be two points in which possible type issues can be caught. By having type definitions, you can define types early to find possible within your code. By maintaining types at runtime, you can prevent incorrect types within the input and find issues that the compiler may have missed. Having two separate checks to ensure that the types are interpreted and used correctly will help ensure the application's security.
TypeScript Security Win: Redundancy in type definitions and maintaining types at runtime will provide an extra net to catch type errors before they become weaknesses.
Freedom means that any one of those developers can do whatever they want in the code. It means that if one developer thinks it is easier to skip type checking or input validation, they can. Or, if someone is in a rush to get something to production, they have the 'freedom' to write insecure code that doesn't protect your application or your customers.
While peer code reviews that you would hope would catch something like this, these weaknesses and bad code can still make it into production if someone misses it or doesn't look. This is true for many applications, or improper input validation wouldn't be third on the 2020 CWE top 25. You want security to be required everywhere within your system, not ignored because one of the developers on your team doesn't like to be constricted by rules.
TypeScript Security Win: TypeScript provides a set of constraints regarding typing, which enforces a higher level of security.
TypeScript Security Win: TypeScript helps with validation and maintaining type safety.
Deveopers across the Internet hate TypeScript. They hate it because it takes away flexibility and freedom. They hate it because it makes them learn and write more code. They even hate it because it doesn't do enough.
None of these reasons are valuable enough to forgo the security features of TypeScript.
TypeScript prevents type issues and adds to input validation efforts. Developers spend more time up front to save time later on. It adds constraints and compiler checks to prevent small mistakes by individual developers from adding up into a weakness.
Isn’t it time to join us in being security champions for TypeScript?