Skip to content

Commit cebbedd

Browse files
authored
Security programming practices and considerations. (#115)
* Security programming practices and considerations. the-draupnir-project/planning#74 * Include examples for hasOwn/getOwn.
1 parent 66b47be commit cebbedd

File tree

1 file changed

+133
-0
lines changed

1 file changed

+133
-0
lines changed

docs/contributing/security.md

Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
# Security
2+
3+
## Programming practices and considerations
4+
5+
Here are some general practices you should follow when programming in
6+
TypeScript, which could otherwise have security implications.
7+
8+
### Property access with user supplied property names
9+
10+
The following example appears a lot in JavaScript code bases, particularly when
11+
exposing configuration objects to the user interface:
12+
13+
```typescript
14+
const config = readConfigFromFile();
15+
const propertyName = readUserInput();
16+
if (object[propertyName] !== undefined) {
17+
doSomething(config[propertyName]);
18+
}
19+
```
20+
21+
This looks innocent enough, but the issue is that this use of property access
22+
also allows the user to access properties from the `Object.prototype`. Which at
23+
best can cause a `TypeError` to be thrown, but at worst can lead to an RCE
24+
vulnerability.
25+
26+
To prevent this, it is recommended to use the `Object.hasOwn` method to guard
27+
user supplied property access. The `@gnuxie/typescript-result` package offers
28+
its own generic `hasOwn` / `getOwn` functions that support type inference.
29+
30+
```typescript
31+
const config = readConfigFromFile();
32+
const propertyName = readUserInput();
33+
if (hasOwn(config, propertyName) !== undefined) {
34+
doSomething(getOwn(config, propertyName));
35+
}
36+
```
37+
38+
#### Resources
39+
40+
- https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Property_accessors
41+
- https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object
42+
- https://github.com/eslint-community/eslint-plugin-security/blob/main/docs/the-dangers-of-square-bracket-notation.md
43+
44+
### ReDoS
45+
46+
Can't provide an explanation for this one but just be careful with capturing
47+
groups and check against the owasp resource below.
48+
49+
#### Resources
50+
51+
- [How regexes got catastrophic](https://www.youtube.com/watch?v=gITmP0IWff0&t=212s).
52+
- https://owasp.org/www-community/attacks/Regular_expression_Denial_of_Service_-_ReDoS
53+
54+
### Prototype pollution
55+
56+
Prototype pollution is the collision of object property names with intrinsic
57+
properties, in most contexts this means properties defined on the
58+
`Object.prototype`, such as the `toString` method.
59+
60+
Prototype pollution typically effects programs in the following situations:
61+
62+
- Using an object as a map or dictionary instead of just using a
63+
[Map](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map).
64+
Leading to problems when keys are derived from user input (including external
65+
APIs).
66+
- Deserializing JSON payloads.
67+
68+
It is a mistake to ever use an object as a generic map, but it happens because
69+
JSON configuration typically forms part of an interface with the program. And
70+
the standard pattern is for JSON to be deserialized to objects through the use
71+
of
72+
[`JSON.parse`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/parse).
73+
And now we're stuck with this history.
74+
75+
Here is a list of properties that you should be considerate of if you ever end
76+
up in a situation where it is important to sanitize property names
77+
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object#object_prototype_properties.
78+
79+
Be sure to also use the jsonReviver provided by Draupnir
80+
https://github.com/the-draupnir-project/Draupnir/blob/0c448ab85e53e24cd4a9ffb81174c04a1a1f381b/src/utils.ts#L517-L531.
81+
82+
### Joe's law
83+
84+
Joe's law: crash, crash, crash, crash crash.
85+
86+
It is important to maintain awareness over situations that a program has
87+
implicitly not been written to handle, and make these explicit by "crashing".
88+
89+
What this means for us is checking state and throwing a
90+
[`TypeError`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypeError).
91+
92+
This prevents the program from running in unanticipated ways and producing
93+
potentially safety and security critical side effects. In other words, failing
94+
to do this can allow attackers to exploit the application. This also makes sure
95+
that developers do not use components inappropriately, in contexts that they
96+
were not written for. Which can also lead to the same outcome. The environment
97+
around code is always changing.
98+
99+
It also provides visibility to both the system administrator and eventually the
100+
developer over the problem. You may think that doing this causes the program to
101+
be less reliable or fault tolerant, but the opposite is actually true. As a
102+
result of these assertions we get feedback from error states faster and can
103+
adjust the program accordingly, leading to a more resilient program in the long
104+
run.
105+
106+
### Matrix mixin validation and parsing
107+
108+
<!-- Cspell:ignore Postel -->
109+
110+
While you may be tempted to treat Matrix event parsing as atomic, this would be
111+
a mistake, especially in a security and safety context. The Matrix specification
112+
places no requirement for events to be "valid" or conform to the provided
113+
schema. The only exception to this are specific event properties that are
114+
validated as part of authorization rules. Even then, this happens implicitly as
115+
part of imperative rule flow rather than declaratively.
116+
117+
Additionally, with the advent of extensible events, Matrix events actually have
118+
multiple parts embedded within them that conform independently to different
119+
schema. These independent units are called mixins.
120+
121+
In most cases Matrix clients will still display malformed events as best they
122+
can, in adherence with the opposite of Joe's law, Postel's law. This allows
123+
malicious actors to craft events specifically to trip up certain matrix clients
124+
in order to make abuse visible only to specific clients.
125+
126+
It is exceptionally important to keep malformed events represented and in the
127+
event processing pipeline as otherwise you can allow users to evade Draupnir
128+
protections.
129+
130+
The approach Draupnir then takes to event parsing is to try parse a minimal
131+
"core" of each mixin and otherwise provide a generic "invalid event" type. Valid
132+
events with invalid mixins will be flagged for redaction to prevent external
133+
abuse.

0 commit comments

Comments
 (0)