Fix V2.2, add annotation that it was found using Fortify
[ssproject1617.git] / report / v2_authentication.tex
1
2 \begin{enumerate}[label={V2.\arabic*}]
3
4 \item
5 \fail{}
6 Verify all pages and resources by default require
7 authentication except those specifically intended to be
8 public (Principle of complete mediation).
9
10 \begin{result}
11 All admin pages are private. Unpublished posts are also private.
12 However, the install submission page does not do any authentication at all,
13 allowing any user to reset the database and claim an admin account.
14 User pages can be viewed (and submitted) by any authenticated user.
15 \end{result}
16
17 \item
18 \fail{}
19 Verify that forms containing credentials are not filled in by
20 the application. Pre-filling by the application implies that
21 credentials are stored in plaintext or a reversible format,
22 which is explicitly prohibited.
23
24 \begin{result}
25 No credentials that come from the database are pre-filled by the application.
26 However, in some forms, the application pre-fills password fields from the
27 request's POST data. This is not necesarry.\footnote{This issue was actually
28 overlooked when auditing manually, and was found when running the Fortify tool.
29 In the initial audit, we only ensured that no internal information (from the
30 database) was leaked in this way.}
31 \end{result}
32
33 \setcounter{enumi}{3}
34
35 \item
36 \pass{}
37 Verify all authentication controls are enforced on the
38 server side.
39
40 \begin{result}
41 All authentication controls (login credentials and client cookies) are
42 enforced by the application. Note however item~\ref{auth:6}, about the
43 security of these controls in the immplementation.
44 \end{result}
45
46 \setcounter{enumi}{5}
47
48 \item\label{auth:6}
49 \fail{}
50 Verify all authentication controls fail securely to ensure
51 attackers cannot log in.
52
53 \begin{result}
54 The input to various forms is not sanitized at all. This makes the implementation
55 in (not only) \code{Users::find} vulnerable to \SQL{} injections. The login form
56 is also vulnerable. Any user can execute arbitrary \SQL{} code from the username field.
57 The following example code can submitted as username in the login form, which
58 will set the password of the \code{admin} user to \code{s3cret}:
59
60 \code{"; UPDATE users SET password='\$1\$OWgsBb90\$Lkko6aZwmp9XOVrFI09Ab0' WHERE \\username='admin' AND 'a' = "a}
61
62 After using this exploit, the attacker (of course) knows the admin password.
63 \end{result}
64
65 \item
66 \pass{}
67 Verify password entry fields allow, or encourage, the use
68 of passphrases, and do not prevent password managers,
69 long passphrases or highly complex passwords being
70 entered.
71
72 \begin{result}
73 The application allows the user to use any password (except ones that contain
74 \SQL{} code).
75 \end{result}
76
77 \item
78 \pass{}
79 Verify all account identity authentication functions (such
80 as update profile, forgot password, disabled / lost token,
81 help desk or IVR) that might regain access to the account
82 are at least as resistant to attack as the primary
83 authentication mechanism.
84
85 \begin{result}
86 The only alternative mechanism for authenticating (except for using
87 vulnerabilities as described in other point) is using the ``Recover
88 password'' functionality. This sends a secret token to the email
89 address owning the account.
90
91 After such a token is used, it cannot be reused, because the token is
92 derived from the password hash (and thus a random salt). Tokens do not
93 expire, however. It would be even better to require that a token be used
94 withing a day (or so) after creation.
95
96 The security of the \SMTP{} connection is at the discretion of the web server.
97 Often these connections are not very secure, but this worry is beyond the
98 scope of this audit.
99 \end{result}
100
101 \item
102 \fail{}
103 Verify that the changing password functionality includes
104 the old password, the new password, and a password
105 confirmation.
106
107 \begin{result}
108 Changing a user's password does not require the original password, nor does the
109 password Changing form request for a password confirmation. This makes it easy
110 to set a wrong password for yourself.
111 \end{result}
112
113 \setcounter{enumi}{11}
114
115 \item
116 \fail{}
117 Verify that all authentication decisions can be logged,
118 without storing sensitive session identifiers or passwords.
119 This should include requests with relevant metadata
120 needed for security investigations.
121
122 \begin{result}
123 The application does not log any notable authentication event.
124 \end{result}
125
126 \item
127 \fail{}
128 Verify that account passwords are one way hashed with a
129 salt, and there is sufficient work factor to defeat brute
130 force and password hash recovery attacks.
131
132 \begin{result}
133 Password are stored in database using the \PHP{} function \code{crypt}. Internally, this
134 function uses salted MD5. This is way too reverse with brute-force attacks using dictionary files.
135
136 Instead it would be better to use the \code{argon2} password hashing algorithm
137 or the \PHP{} \code{password\_hash} function (which currently uses BCRYPT).
138 \end{result}
139
140 \setcounter{enumi}{15}
141
142 \item
143 \fail{}
144 Verify that credentials are transported using a suitable
145 encrypted link and that all pages/functions that require a
146 user to enter credentials are done so using an encrypted
147 link.
148
149 \begin{result}
150 The app allows admin users to log in over \HTTP{}. This is insecure, as it allows
151 eavesdroppers to intercept password.
152 The app should force \HTTPS{} for at least the login form, the \code{admin\_controller} and
153 for the installation script (because the users posts secrets like the database
154 password to this page).
155 \end{result}
156
157 \item
158 \pass{}
159 Verify that the forgotten password function and other
160 recovery paths do not reveal the current password and
161 that the new password is not sent in clear text to the user.
162
163 \begin{result}
164 No password is stored in plain text. The password recovery path works with
165 a secret token, which is used to reset the password. Although this token
166 is derived from the password hash, it does not reveal any secret
167 information.
168 \end{result}
169
170 \item
171 \fail{}
172 Verify that information enumeration is not possible via
173 login, password reset, or forgot account functionality.
174
175 \begin{result}
176 All these forms are vulnerable to \SQL{} injection attacks. So any information
177 can leak any information from the database.
178 \end{result}
179
180 \item
181 \pass{}
182 Verify there are no default passwords in use for the
183 application framework or any components used by the
184 application (such as “admin/password”).
185
186 \begin{result}
187 No secrets are initialized by predefined values. The admin user will have
188 username \code{admin} by default. This is no secret and therefore not
189 considered unsafe.
190 \end{result}
191
192 \item
193 \fail{}
194 Verify that anti-automation is in place to prevent breached
195 credential testing, brute forcing, and account lockout
196 attacks.
197
198 \begin{result}
199 No anti-automation measures are deployed.
200
201 This is needed for:
202 \begin{itemize}
203 \item Email validation, to harden brute force email address discovery
204 \item Installation database check, to prevent guessing attacks for the database password
205 \item Login, to prevent login guessing
206 \item And comment submission, to prevent spam, phishing et cetera (by
207 using some CAPTCHA software).
208 \end{itemize}
209 \end{result}
210
211 \item
212 \fail{}
213 Verify that all authentication credentials for accessing
214 services external to the application are encrypted and
215 stored in a protected location.
216
217 \begin{result}
218 The database credentials are hardcoded in \code{config.php}. While it
219 would be better to pass secrets as environment variables, this is not
220 really bad practice.
221
222 However, the installation instructions state the following:
223 \begin{verbatim}
224 Change the file permissions to allow all users write access to the folder
225 you extracted testcms to.
226 \end{verbatim}
227 This implies making the configuration file readable for all users on the
228 system. This information should not be accessible for any user other than
229 running the \PHP{} script.
230 \end{result}
231
232 \item
233 \pass{}
234 Verify that forgotten password and other recovery paths
235 use a \TOTP{} or other soft token, mobile push, or other
236 offline recovery mechanism. Use of a random value in an
237 e-mail or SMS should be a last resort and is known weak.
238
239 \begin{result}
240 The password recovery path uses a random looking token. It is sent over
241 e-mail, which is considered weak (but not unsafe).
242 \end{result}
243
244 \notapplicable{\item
245 Verify that account lockout is divided into soft and hard
246 lock status, and these are not mutually exclusive. If an
247 account is temporarily soft locked out due to a brute force
248 attack, this should not reset the hard lock status.
249
250 % The application has not implemented any lockout mechanisms.
251 }
252
253 \notapplicable{\item
254 Verify that if shared knowledge based questions (also
255 known as ``secret questions'') are required, the questions
256 do not violate privacy laws and are sufficiently strong to
257 protect accounts from malicious recovery.}
258
259 \item
260 \fail{}
261 Verify that the system can be configured to disallow the
262 use of a configurable number of previous passwords.
263
264 \begin{result}
265 The system does not remember any previously used passwords and does not
266 require variation in the use of different passwords.
267 \end{result}
268
269 \notapplicable{\item
270 Verify that risk based re-authentication, two factor or
271 transaction signing is in place for high value transactions.}
272
273 % There are no (really) risk based action or which re-authentication would be
274 % fit
275
276 \item
277 \fail{}
278 Verify that measures are in place to block the use of
279 commonly chosen passwords and weak passphrases.
280
281 \begin{result}
282 No password strengthening measures are implemented. The app should
283 use some password strength estimator like \texttt{zxcvbn}\footnote{\url{https://github.com/dropbox/zxcvbn}}.
284 \end{result}
285
286 \item
287 \fail{}
288 Verify that all authentication challenges, whether
289 successful or failed, should respond in the same average
290 response time.
291
292 \begin{result}
293 String comparisation for checking password hases and password reset tokens
294 are not in constant time.
295 \end{result}
296
297 \item
298 \fail{}
299 Verify that secrets, \API{} keys, and passwords are not
300 included in the source code, or online source code
301 repositories.
302
303 \begin{result}
304 The database credentials are hard coded in \code{config.php}. These
305 credentials should ideally be passed using environment variables.
306 \end{result}
307
308 \setcounter{enumi}{30}
309
310 \notapplicable{\item
311 Verify that if an application allows users to authenticate,
312 they can authenticate using two-factor authentication or
313 other strong authentication, or any similar scheme that
314 provides protection against username + password
315 disclosure.}
316
317 \item
318 \fail{}
319 Verify that administrative interfaces are not accessible to
320 untrusted parties.
321
322 \begin{result}
323 Any authenticated user is allowed to view and use the administrative
324 interface. A separation should be made between administrators and normal
325 users.
326 \end{result}
327
328 \item
329 \pass{}
330 Browser autocomplete, and integration with password
331 managers are permitted unless prohibited by risk based
332 policy.
333
334 \begin{result}
335 Browser autocomplete functionality is not restricted in any way.
336 \end{result}
337
338 \end{enumerate}