You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
4. Use a predictable prefix and suffix to integrate with various secret scanning services (ex. Github's Secret Scanning)
37
39
38
40
# Motivation
39
41
40
42
## Why?
41
43
42
-
Sentry currently provides several strong options to secure a user's account, including SSO, SAML, and 2FA options. However our approach to handling API tokens is not as mature. We have two major issues with the current API token implementation:
44
+
Sentry currently provides several strong options to secure a user's account, including SSO, SAML, and 2FA options.
45
+
However our approach to handling API tokens is not as mature. We have two major issues with the current API token implementation:
43
46
44
47
1. Tokens are stored as plaintext in the database, increasing the risk of exposure
45
48
2. Tokens are visible as plaintext in the Sentry UI
@@ -54,18 +57,21 @@ When a user creates an API token, they **have the option to provide it an arbitr
54
57
55
58
Existing API tokens, should be hashed and their original value discarded.
56
59
57
-
A notice in the Sentry UI should be presented to suggest the user rotate and generate a new token to the new and improved version.
60
+
A notice in the Sentry UI should be presented to suggest the user rotate and generate a new token to gain the benefits of the improved version.
58
61
59
62
### Token Format
60
63
61
-
We need a predictable token format in order to integrate properly with secret scanning services. Our current format is a 64 character alphanumeric string. This is insufficient and would likely produce a high amount of false positives in tooling like [TruffleHog](https://github.com/trufflesecurity/trufflehog), [detect-secrets](https://github.com/Yelp/detect-secrets), [Github's Secret Scanning](https://docs.github.com/en/code-security/secret-scanning/about-secret-scanning), etc.
64
+
We need a predictable token format in order to integrate properly with secret scanning services. Our current format is a 64 character alphanumeric string. This is insufficient and
65
+
would likely produce a high amount of false positives in tooling like [TruffleHog](https://github.com/trufflesecurity/trufflehog), [detect-secrets](https://github.com/Yelp/detect-secrets),
66
+
[Github's Secret Scanning](https://docs.github.com/en/code-security/secret-scanning/about-secret-scanning), etc.
62
67
63
-
The suggested pattern is `snty[a-zA-Z]_[a-zA-Z0-9]{64}io`. The character _after_`snty` will be used to identify the token type.
68
+
The suggested pattern is `sntry[a-zA-Z]_[a-zA-Z0-9]{64}`. The character _after_`sntry` will be used to identify the token type.
64
69
65
70
For example:
66
71
67
-
-`sntyu_a1b2c3...` - identifies a **user** API token
68
-
-`sntya_a1b2c3...` - identifies an **API Application** token
72
+
-`sntryu_a1b2c3...` - identifies a **user** API token
73
+
-`sntrya_a1b2c3...` - identifies an **API Application** token
74
+
-`sntrys_a1b2c3...` - identifies an **Organization Auth** token
69
75
70
76
### Backend Token Hygiene
71
77
@@ -92,7 +98,8 @@ At a high-level, we will need to be able to:
92
98
93
99
# Background
94
100
95
-
Accidental credential leaks [happen](https://github.com/ChALkeR/notes/blob/master/Do-not-underestimate-credentials-leaks.md). Even though we provide several tools for users to limit the storage of sensitive information in Sentry it can still happen.
101
+
Accidental credential leaks [happen](https://github.com/ChALkeR/notes/blob/master/Do-not-underestimate-credentials-leaks.md). Even though we provide several
102
+
tools for users to limit the storage of sensitive information in Sentry it can still happen.
96
103
97
104
Our support for various authentication methods (including 2FA, SSO, and SAML) helps mitigate access of potentially sensitive information, but API tokens cannot support these additional authentication gates.
98
105
@@ -102,18 +109,47 @@ We can help customers further protect their accounts and data by providing a mea
102
109
103
110
## Option #1
104
111
105
-
This option strives to limit impact to the database by avoiding large bulk operations. To do this we'll distribute the complete implementation over two releases. This also allows for a smooth transition of self-hosted instances keeping pace with releases.
112
+
This option strives to limit impact to the database by avoiding large bulk operations and maintain backwards compatibility. To do this we'll distribute the complete implementation over at least two releases.
113
+
This also allows for a smooth transition of self-hosted instances keeping pace with releases.
106
114
107
-
**In the first release:**
115
+
First, we will need to support naming and showing a mostly obfuscated token in the UI to help users identify them.
108
116
109
-
1. The frontend is updated to no longer display the token value for existing tokens.
110
-
2. The frontend is updated to accept a `name` when creating new tokens.
111
-
3. A notification/warning in the UI should be displayed recommending users recreate their tokens, resulting in the new token version.
112
-
4. New tokens are only displayed once at creation time to the user.
113
-
5. New tokens are created following the new format.
117
+
1. The frontend is updated to no longer display the token value for existing tokens. [#61941](https://github.com/getsentry/sentry/pull/61941)
118
+
2. Nullable `name` and `token_last_characters` fields are added to the `ApiToken` model.
119
+
- New `ApiToken`s created should automatically have the `token_last_characters` populated based on an option.
120
+
The option is required in order to properly test the upcoming backfill migration. [#62972](https://github.com/getsentry/sentry/pull/62972)
121
+
3. A backfill migration is created and ran to fill in the `token_last_characters` for all `ApiToken` entries. [#63342](https://github.com/getsentry/sentry/pull/63342)
122
+
4. Change the `ApiToken` serializer to send the `token_last_characters` in the response for use in the frontend. [#63473](https://github.com/getsentry/sentry/pull/63473)
123
+
5. Change the frontend to use the new `token_last_characters` value and show an obfuscated token in the UI. [#63485](https://github.com/getsentry/sentry/pull/63485)
124
+
6. Update the backend serializer for `ApiToken` to accept and return an optional `name` field.
125
+
7. Update the frontend to support creation of a token with a `name` and displaying of the `name` when listing tokens.
126
+
127
+
Second, we will need to secure the tokens. This involves four primary goals.
128
+
129
+
- Tokens are hashed in the database
130
+
- Newly created user auth tokens have the `sntryu_` prefix
131
+
- Newly created user API application tokens have the `sntrya_` prefix
132
+
- We encourage users in the UI via a notification/banner to recreate their tokens in order to get new ones with a prefix
133
+
134
+
1. Nullable `hashed_token` and `hashed_refresh_token` fields are added to the `ApiToken` model
135
+
2. The `save()` method on `ApiToken` is updated to calculate and store the token's SHA-256 hash in `hashed_token`.
136
+
3. Update the `UserAuthTokenAuthentication` middleware to:
137
+
138
+
1. Caculate the SHA-256 hash and use the hash value for the table lookup on the `hashed_token` or `hashed_refresh_token` column.
139
+
2. If the hash is not found, use the plaintext token for the table lookup on the `token` or `refresh_token` column.
140
+
3. If it is a valid token that does not yet have a hashed value, hash it and update the respective `hashed_` columns for the entry in the database.
141
+
142
+
> _This helps us avoid a large backfill migration in the future. As tokens are used, they'll be hashed and their corresponding
143
+
> row will be updated. We will still need a backfill migration, but this allows a slow and safer transition to hashed tokens._
144
+
>
145
+
> _It's important to note that this does not update the token to the new prefixed format._
146
+
147
+
4. A notification/warning in the UI should be displayed recommending users recreate their tokens, resulting in the new token version.
148
+
5. New tokens are only displayed once at creation time to the user.
149
+
6. New tokens are created following the new format.
114
150
- A Django migration will be needed to add fields: `hashed_token`, `version`, and `name`.
115
151
- legacy tokens will be `version = 1` and new tokens `version = 2`
116
-
6. As old tokens are used, they are hashed and stored in the database.
152
+
7. As old tokens are used, they are hashed and stored in the database.
117
153
- This does not update the token to the new format.
118
154
- The plaintext token value should be removed in this action.
119
155
@@ -129,16 +165,18 @@ Instead of slowly generating the hashed token values over time of the legacy tok
129
165
130
166
### Drawbacks
131
167
132
-
- This is less than ideal because of the potential performance impact while the migration mutates each row in the table. Potential impacts to self-hosted installs would be unknown as well.
168
+
- This is less than ideal because of the potential performance impact while the migration mutates each row in the table.
169
+
- Potential impact to self-hosted installs where this is a large amount of rows in the table.
133
170
134
171
## Option #3
135
172
136
-
To avoid the two different token versions, we could automatically prepend the prefix `sntyx_` (with `x` just being a placeholder here) and suffix `io`. We would then follow a similar approach to Option #1 or Option #2 to generate the hashed values.
173
+
To avoid the two different token versions, we could automatically prepend the prefix `sntryx_` (with `x` just being a placeholder here).
174
+
We would then follow a similar approach to Option #1 or Option #2 to generate the hashed values.
137
175
138
176
### Drawbacks
139
177
140
-
- Users would not be able to benefit from the Github Secrets Scanning since they would still be using their 64 character alphanumeric string without the prefix and suffix.
141
-
- Authentication views/logic would become more complex with branching code to handle the with and without prefix + suffix cases.
178
+
- Users would not be able to benefit from the Github Secrets Scanning since they would still be using their 64 character alphanumeric string without the prefix.
179
+
- Authentication views/logic would become more complex with branching code to handle the with and without prefix cases.
0 commit comments