-
Notifications
You must be signed in to change notification settings - Fork 4
/
add-to-your-blog.php
executable file
·357 lines (319 loc) · 13.6 KB
/
add-to-your-blog.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
<?php
/* Known Vulnerabilities:
SQL injection,
Cross Site Scripting,
Cross Site Request Forgery,
Application Exception Output,
HTML injection,
Method Tampering
Known Vulnerable Output: Name, Comment, "Add blog for" title,
*/
/* Instantiate CSRF Protection object */
require_once (__ROOT__.'/classes/CSRFTokenHandler.php');
$lCSRFTokenHandler = new CSRFTokenHandler(__ROOT__.'/owasp-esapi-php/src/', $_SESSION["security-level"], "register-user");
if (!isSet($logged_in_user)) {
throw new Exception("$logged_in_user is not set. Page add-to-your-blog.php requires this variable.");
}// end if
switch ($_SESSION["security-level"]){
case "0": // This code is insecure
// DO NOTHING: This is insecure
$lEncodeOutput = FALSE;
$lLoggedInUser = $logged_in_user;
$lTokenizeAllowedMarkup = FALSE;
$lProtectAgainstSQLInjection = FALSE;
$lEnableJavaScriptValidation = FALSE;
$lEnableHTMLControls = FALSE;
$lProtectAgainstMethodTampering = FALSE;
break;
case "1": // This code is insecure
// DO NOTHING: This is insecure
$lEncodeOutput = FALSE;
$lLoggedInUser = $logged_in_user;
$lTokenizeAllowedMarkup = FALSE;
$lProtectAgainstSQLInjection = FALSE;
$lEnableJavaScriptValidation = TRUE;
$lEnableHTMLControls = TRUE;
$lProtectAgainstMethodTampering = FALSE;
break;
case "2":
case "3":
case "4":
case "5": // This code is fairly secure
/*
* NOTE: Input validation is excellent but not enough. The output must be
* encoded per context. For example, if output is placed in HTML,
* then HTML encode it. Blacklisting is a losing proposition. You
* cannot blacklist everything. The business requirements will usually
* require allowing dangerous charaters. In the example here, we can
* validate username but we have to allow special characters in passwords
* least we force weak passwords. We cannot validate the signature hardly
* at all. The business requirements for text fields will demand most
* characters. Output encoding is the answer. Validate what you can, encode it
* all.
*/
// encode the output following OWASP standards
// this will be HTML encoding because we are outputting data into HTML
$lEncodeOutput = TRUE;
/* Business Problem: Sometimes the business requirements define that users
* should be allowed to use some HTML markup. If unneccesary, this is a
* bad idea. Output encoding will naturally kill any users attempt to use HTML
* in their input, which is exactly why we use output encoding.
*
* If the business process allows some HTML, then those HTML items are elevated
* from "mallicious input" to "direct object refernces" (a resource to be enjoyed).
* When we want to restrict a user to using to "direct object refernces" (a
* resource to be enjoyed) responsibly, we use mapping. Mapping allows the user
* to chose from a "system generated" (that's us programmers) set of tokens
* to pick from. We need to assure that the user either chooses one of the tokens
* we offer, or our system rejects the request. To put it bluntly, either the user
* follows the rules, or their output is encoded. Period.
*/
$lTokenizeAllowedMarkup = TRUE;
/* If we are in secure mode, we need to protect against SQLi */
$lProtectAgainstSQLInjection = TRUE;
/* Note that $MySQLHandler->escapeDangerousCharacters is ok but not the best defense. Stored
* Procedures are a much more powerful defense, run much faster, can be
* trapped in a schema, can run on the database, and can be called from
* any number of web applications. Stored procs are the true anti-pwn.
* There are 3 ways that stored procs can be made vulenrable by developers,
* but they are safe by default. Queries are vulnerable by default.
*/
$lLoggedInUser = $MySQLHandler->escapeDangerousCharacters($logged_in_user);
/*
* There is no security in JS validation. You must validate on the server.
* JS is easy to bypass.
*/
$lEnableJavaScriptValidation = TRUE;
$lEnableHTMLControls = TRUE;
$lProtectAgainstMethodTampering = TRUE;
break;
}// end switch
$lNewCSRFTokenForNextRequest = $lCSRFTokenHandler->generateCSRFToken();
$lFormSubmitted = isSet($_POST["add-to-your-blog-php-submit-button"]);
/* ----------------------------------------
* Insert user's new blog entry
* ----------------------------------------
* precondition: $logged_in_user is not null
*/
if($lFormSubmitted){
try {
if ($lProtectAgainstMethodTampering) {
$lPostedCSRFToken = $_POST['csrf-token'];
}else{
$lPostedCSRFToken = $_REQUEST['csrf-token'];
}//end if
if (!$lCSRFTokenHandler->validateCSRFToken($lPostedCSRFToken)){
throw (new Exception("Security Violation: Cross Site Request Forgery attempt detected.", 500));
}// end if
// Grab inputs
if ($lProtectAgainstSQLInjection){
// This might prevent SQL injection on the insert.
$lBlogEntry = $MySQLHandler->escapeDangerousCharacters($_POST["blog_entry"]);
}else{
$lBlogEntry = $_REQUEST["blog_entry"];
}// end if
/* Some dangerous markup allowed. Here we tokenize it for storage. */
if ($lTokenizeAllowedMarkup){
$lBlogEntry = str_ireplace('<b>', BOLD_STARTING_TAG, $lBlogEntry);
$lBlogEntry = str_ireplace('</b>', BOLD_ENDING_TAG, $lBlogEntry);
$lBlogEntry = str_ireplace('<i>', ITALIC_STARTING_TAG, $lBlogEntry);
$lBlogEntry = str_ireplace('</i>', ITALIC_ENDING_TAG, $lBlogEntry);
$lBlogEntry = str_ireplace('<u>', UNDERLINE_STARTING_TAG, $lBlogEntry);
$lBlogEntry = str_ireplace('</u>', UNDERLINE_ENDING_TAG, $lBlogEntry);
}// end if $lTokenizeAllowedMarkup
// weak server-side input validation. not good enough.
if(strlen($lBlogEntry) > 0){
$lValidationFailed = FALSE;
try {
$SQLQueryHandler->insertBlogRecord($lLoggedInUser, $lBlogEntry);
} catch (Exception $e) {
echo $CustomErrorHandler->FormatError($e, "Error inserting blog for " . $lLoggedInUser);
}//end try
try {
$LogHandler->writeToLog("Blog entry added by: " . $lLoggedInUser);
} catch (Exception $e) {
// do nothing
}//end try
}else{
$lValidationFailed = TRUE;
}// end if(strlen($lBlogEntry) > 0)
} catch (Exception $e) {
echo $CustomErrorHandler->FormatError($e, "Error inserting blog");
}// end try
}else {
$lValidationFailed = FALSE;
}// end if isSet($_POST["add-to-your-blog-php-submit-button"])
?>
<!-- Bubble hints code -->
<?php
try{
$lReflectedXSSExecutionPointBallonTip = $BubbleHintHandler->getHint("ReflectedXSSExecutionPoint");
$lXSRFVulnerabilityAreaBallonTip = $BubbleHintHandler->getHint("XSRFVulnerabilityArea");
$lHTMLandXSSandSQLInjectionPointBallonTip = $BubbleHintHandler->getHint("HTMLandXSSandSQLInjectionPoint");
} catch (Exception $e) {
echo $CustomErrorHandler->FormatError($e, "Error attempting to execute query to fetch bubble hints.");
}// end try
?>
<script type="text/javascript">
$(function() {
$('[ReflectedXSSExecutionPoint]').attr("title", "<?php echo $lReflectedXSSExecutionPointBallonTip; ?>");
$('[ReflectedXSSExecutionPoint]').balloon();
$('[XSRFVulnerabilityArea]').attr("title", "<?php echo $lXSRFVulnerabilityAreaBallonTip; ?>");
$('[XSRFVulnerabilityArea]').balloon();
$('[HTMLandXSSandSQLInjectionPoint]').attr("title", "<?php echo $lHTMLandXSSandSQLInjectionPointBallonTip; ?>");
$('[HTMLandXSSandSQLInjectionPoint]').balloon();
});
</script>
<!-- BEGIN HTML OUTPUT -->
<script type="text/javascript">
var onSubmitBlogEntry = function(/* HTMLForm */ theForm){
<?php
if($lEnableJavaScriptValidation){
echo "var lInvalidBlogPattern = /\'/;";
}else{
echo "var lInvalidBlogPattern = /*/;";
}// end if
?>
if(theForm.blog_entry.value.search(lInvalidBlogPattern) > -1){
alert('Single-quotes are not allowed. Dont listen to security people. Everyone knows if we just filter dangerous characters, XSS is not possible.\n\nWe use JavaScript defenses combined with filtering technology.\n\nBoth are such great defenses that you are stopped in your tracks.');
return false;
}
};// end JavaScript function onSubmitBlogEntry()
</script>
<div class="page-title">Welcome To The Blog</div>
<?php include_once (__ROOT__.'/includes/back-button.inc'); ?>
<?php include_once (__ROOT__.'/includes/hints/hints-menu-wrapper.inc'); ?>
<fieldset>
<legend>Add New Blog Entry</legend>
<form action="index.php?page=add-to-your-blog.php"
method="post"
enctype="application/x-www-form-urlencoded"
onsubmit="return onSubmitBlogEntry(this);"
id="idBlogForm"
>
<input name="csrf-token" type="hidden" value="<?php echo $lNewCSRFTokenForNextRequest; ?>" />
<span>
<a href="./index.php?page=view-someones-blog.php" style="text-decoration: none;">
<img style="vertical-align: middle;" src="./images/magnifying-glass-icon.jpeg" height="32px" width="32px" />
<span style="font-weight:bold;"> View Blogs</span>
</a>
</span>
<table style="margin-left:auto; margin-right:auto;">
<tr id="id-bad-blog-entry-tr" style="display: none;">
<td class="error-message">
Validation Error: Blog entry cannot be blank
</td>
</tr>
<tr><td></td></tr>
<tr>
<td id="id-blog-form-header-td" ReflectedXSSExecutionPoint="1" class="form-header">
Add blog for <?php echo $lLoggedInUser?>
</td>
</tr>
<tr><td></td></tr>
<tr>
<td class="report-header">
Note: <b>,<i> and <u> are now allowed in blog entries
</td>
</tr>
<tr>
<td>
<textarea name="blog_entry" HTMLandXSSandSQLInjectionPoint="1" rows="8" cols="65"
autofocus="autofocus"
<?php
if ($lEnableHTMLControls) {
echo('minlength="1" maxlength="100" required="required"');
}// end if
?>
></textarea>
</td>
</tr>
<tr><td></td></tr>
<tr>
<td style="text-align:center;">
<input name="add-to-your-blog-php-submit-button" XSRFVulnerabilityArea="1" class="button" type="submit" value="Save Blog Entry" />
</td>
</tr>
<tr><td></td></tr>
</table>
</form>
</fieldset>
<?php
if ($lValidationFailed) {
echo '<script>document.getElementById("id-bad-blog-entry-tr").style.display="";</script>';
}// end if ($lValidationFailed)
?>
<?php
/* Display current user's blog entries */
try {
try {
/* Note that the logged in user could be used for SQL injection */
$lQueryResult = $SQLQueryHandler->getBlogRecord($lLoggedInUser);
} catch (Exception $e) {
echo $CustomErrorHandler->FormatError($e, "Error selecting blog entries for " . $lLoggedInUser . ": " . $lQuery);
}//end try
try {
$LogHandler->writeToLog("Selected blog entries for " . $lLoggedInUser);
} catch (Exception $e) {
echo $CustomErrorHandler->FormatError($e, "Error writing selected blog entries to log");
}// end try
echo '<div> </div>
<span>
<a href="./index.php?page=view-someones-blog.php">
<img style="vertical-align: middle;" src="./images/magnifying-glass-icon.jpeg" height="32px" width="32px" />
<span style="font-weight:bold; text-decoration: none;">View Blogs</span>
</a>
</span>';
echo '<table border="1px" width="90%" class="results-table">';
echo ' <tr class="report-header">
<td colspan="4">'.$lQueryResult->num_rows.' Current Blog Entries</td>
</tr>
<tr class="report-header">
<td> </td>
<td>Name</td>
<td>Date</td>
<td>Comment</td>
</tr>';
$lRowNumber = 0;
while($lRecord = $lQueryResult->fetch_object()){
$lRowNumber++;
if(!$lEncodeOutput){
$lBloggerName = $lRecord->blogger_name;
$lDate = $lRecord->date;
$lComment = $lRecord->comment;
}else{
$lBloggerName = $Encoder->encodeForHTML($lRecord->blogger_name);
$lDate = $Encoder->encodeForHTML($lRecord->date);
$lComment = $Encoder->encodeForHTML($lRecord->comment);
}// end if
/* Some dangerous markup allowed. Here we restore the tokenized output.
* Note that using GUIDs as tokens works well because they are
* fairly unique plus they encode to the same value.
* Encoding wont hurt them.
*
* Note: Mutillidae is weird. It has to be broken and unbroken at the same time.
* Here we un-tokenize our output no matter if we are in secure mode or not.
*/
$lComment = str_ireplace(BOLD_STARTING_TAG, '<span style="font-weight:bold;">', $lComment);
$lComment = str_ireplace(BOLD_ENDING_TAG, '</span>', $lComment);
$lComment = str_ireplace(ITALIC_STARTING_TAG, '<span style="font-style: italic;">', $lComment);
$lComment = str_ireplace(ITALIC_ENDING_TAG, '</span>', $lComment);
$lComment = str_ireplace(UNDERLINE_STARTING_TAG, '<span style="border-bottom: 1px solid #000000;">', $lComment);
$lComment = str_ireplace(UNDERLINE_ENDING_TAG, '</span>', $lComment);
echo "<tr>
<td>{$lRowNumber}</td>
<td ReflectedXSSExecutionPoint=\"1\">{$lBloggerName}</td>
<td>{$lDate}</td>
<td ReflectedXSSExecutionPoint=\"1\">{$lComment}</td>
</tr>\n";
}//end while $lRecord
echo "</table><div> </div>";
} catch (Exception $e) {
echo $CustomErrorHandler->FormatError($e, $lQuery);
}// end try
?>
<?php
if ($lFormSubmitted) {
echo $lCSRFTokenHandler->generateCSRFHTMLReport();
}// end if
?>