After completing these activities you should be able to:
"G O N A V Y !" 50 times. We've already done this as a client side script, now we'll do this as a server side script. To start off with, look at these links:
The code for the server side is almost the same as the client side. The big difference is: what gets executed where, and what actually gets sent. The following should illustrate the differences:
Client Side – client sends GET for ex0.html
|
|||||
| Server finds |
<HTML>
<HEAD> ... </HEAD>
<BODY>
<SCRIPT type="text/javascript">
var iter = 0;
while (iter < 50) {
document.write("G O N A V Y ! ");
iter = iter + 1;
}
</SCRIPT>
</BODY>
</HTML>
|
, server sends |
<HTML>
<HEAD> ... </HEAD>
<BODY>
<SCRIPT type="text/javascript">
var iter = 0;
while (iter < 50) {
document.write("G O N A V Y ! ");
iter = iter + 1;
}
</SCRIPT>
</BODY>
</HTML>
|
, browser executes & renders as |
|
Server Side – client sends GET for ex0.py |
|||||
| server finds & executes |
function () {
var out = "";
var iter = 0;
while(iter < 50) {
out = out + "G O N A V Y ! ";
iter = iter + 1;
}
return out;
}
|
, server sends |
|
, browser renders as |
|
| Client Side Fahrenheit-to-Celsius Converter | Server Side Fahrenheit-to-Celsius Converter |
|---|---|
|
(shift+refresh to return) |
(browser back-button to return) |
<form name="clientSide" onsubmit="return false;">
<input type="text" name="fahrenheit"> °F
<input type="button" value="Convert"
onclick="var f = document.forms.clientSide.fahrenheit.value;
var c = 5/9*(f - 32);
document.body.innerHTML = c + ' °C';
">
</form>
|
<form name="serverSide"
action="https://courses.cyber.usna.edu/SY110/resources/scripts/f2c.py"
method="get">
<input type="text" name="fahrenheit"> °F
<input type="button" onclick="submit();" value="Convert">
</form> |
Verify that both work, then try to look for differences in how they work from the user's perspective. You should notice that the client side version keeps you at the same URL. The client side form has onsubmit="return false;" and a small Mathematical computation after the onclick for the button input. The server side version, however, takes you to a different URL — and a strange one at that! The server side URL ends with something like:
f2c.py?fahrenheit=45Additionally, while the form also has
onsubmit="return false" there are two additional attributes within the form start tag: action and method, and finally, the onclick for the button input has the value "submit()". These are the key differences that tell you, the user, that the page will send input to the server for processing.method attribute. The GET method sends the user's input as part of the URL. Recall that the server will record the file system path of a GET request URL in its server access logs. So, in this case, the file system path contains the user's input and this means that the value a user enters into a form executing a server side script will be permanently entered into the server's access logs.name=value pairs that give the names and values of the parameters the server side script will use as inputs (if we include multiple, they will be separated by an ampersand). Interestingly, we don't need the nice fancy web page with the form field and button in order to use this conversion script. Simply enter the URL
https://courses.cyber.usna.edu/SY110/resources/scripts/f2c.py?fahrenheit=78in your browser's address bar with different values for "fahrenheit" and you can get the conversions directly. In other words, without typing anything into the form and without clicking the button, you can send a GET request. The server still processes your input, sending the browser the results. This presents a potential security risk if the server side program (script) has not taken into account unanticipated user input.
f2c.py |
function(fahrenheit) {
var c = 5/9*(fahrenheit - 32);
return c + ' °C';
} |
f2c.py is very simple, as you see - the code performs that same Mathematical computation that the client side version performed. In looking at it, don't worry about the function(fahrenheit){ ... }
wrapped around the code except to accept that it's there, and to know that inside the ( )'s is/are the parameter (input) names that the code needs to execute. The corresponding form on the page will contain an input element for each of these function parameters in the ( )'s for the server side script. So, in the case of the f2c.html file, there is a form with a text box that accepts user input: <input type="text" name = "fahrenheit"> which is not a coincidence. The names of the inputs in the form must match the parameters for the server side script.
returning a string. That string becomes the <body> contents of the HTML code that gets sent to the browser. These server side scripts can do many things, including read from and write to files sitting on the server. How one would do that with JavaScript is way outside the scope of this course and, actually, is dependent on the particular JavaScript interpreter you're using. We're using the JSEXT interpreter, in case you'd like to look into this more deeply.
Now, let's turn to the browser's part in a server side scripted system. We could make use of server side scripts using only the tools we already know: we could write client side scripts that build a URL string with the name/value pairs determined by some interaction with the user. However, that's not how it's usually done. Usually server side scripts are called automatically using a feature of forms we haven't yet discussed: submit. Form elements were actually introduced specifically to get user input and call server side scripts. There is a DOM function called submit()
that automatically grabs the value attribute for each named form input element, and builds the name/value pairs from the names and values of those input elements. The first part of the URL that will be called, i.e. everything
before the "?", comes from the form's action attribute. Recall the server side example's form element was defined like this:
<form name="cs"
action="https://courses.cyber.usna.edu/SY110/resources/scripts/f2c.py"
method="get">
<input type="text" name="fahrenheit"> °F
<input type="button" onclick="submit()" value="Convert">
</form>
Here's how things work:
fahrenheit named text-input.Convert button.onclick script is executed, which simply calls the submit() function from the DOM - this is a client side action.submit function builds a URL as follows (because the form's method attribute is GET):
https://courses.cyber.usna.edu/SY110/resources/scripts/f2c.py?fahrenheit=78.3
\___________________________________________________________/ \________/ \__/
| | |
FORM's "action" attribute INPUT INPUT element's
element's value
name
Now we are in a position to understand why our client side only use of forms always included the form attribute definition onsubmit="return false;", it was to stop the browser from trying to form a URL and pull up a new page!
Note: if you hit enter after typing something into the text box, the form is automatically submitted. This can be turned off, but it's a bit of a pain, since Explorer does it differently than the other browsers. One way to do this
is to keep the form element's onsubmit="return false;" attribute definition. When our button calls submit(), the form's onsubmit is bypassed.
Lots of businesses and individuals are moving to "cloud storage", which means that a big company (like amazon.com) stores your data for you, and you / your company can access the data from anywhere. Filepicker.io is a JavaScript library (https://api.filepicker.io/v0/filepicker.js) that you include in your HTML just like we've already done, and it provides easy-to-use functions that allow the website to give users the ability to upload files to cloud storage space owned by the website. Now, the website will be charged more or less money for that cloud storage depending on how many gigabytes of storage they use. For that reason (and others) the site needs to limit the size of files that can be uploaded. Filepicker.io provides that functionality, but checks the file size client side. In the blog post, Mr. Foster demonstrates that he can send the same GET requests to cause a file to be uploaded to
a site's cloud storage that the filepicker.io library would send from a script that he wrote (a glorified application of netcat). The difference is that, with his script, the client side validation code is completely bypassed. Thus, he can lie about the file-size when he uploads with his script, and can upload as big a file as he likes to the website's cloud storage ... which could end up costing big money!
Simply put, from a server's perspective, user input into a web application - whether from HTML forms, URLs, cookies, or client-side scripts - cannot be trusted. As such, web applications must check user input before using it, especially when that input affects server-side behavior.
The general process of checking and handling untrusted input is commonly referred to as input validation or input sanitization. (These terms are sometimes used interchangeably; to be more precise, validation determines whether input meets acceptable criteria, such as type, format, length, or range. Sanitization modifies input for security purposes so that it can be safely used.) Regardless of terminology, both are part of defending a website against malicious or unreasonable input.
Input checks may be performed on either the client or the server. Client-side input checks are typically implemented using JavaScript and are intended primarily to improve usability. For example, client-side code can quickly alert a user that an email address is not properly formatted, reducing unnecessary network traffic by preventing obviously invalid requests from being sent to the server.
However, client-side checks do not provide reliable security. A server cannot assume that client-side code has executed, nor can it trust that input has not been altered. A user can bypass client-side checks by disabling JavaScript, modifying the HTML source, or manually crafting a request. Therefore, all security-relevant input checks must be enforced on the server.
Consider a server-side script that prints a string a specified number of times. If the script accepts a user-supplied value indicating how many times to print the string, unrestricted input could cause excessive server computation or network usage. To prevent this, the server must check that the input falls within acceptable limits.
The following server-side function prints the string GONAVY! a number of times specified by the parameter N:
function (N) {
var out = "";
var iter = 0;
while (iter < N) {
out = out + "G O N A V Y ! ";
iter = iter + 1;
}
return out;
}
Suppose this function is intended to be invoked using a URL with a name/value pair such as ?N=800, with the value of N supplied by the user through an HTML form. A client-side script may be used to prevent the form from being submitted when N exceeds a chosen limit, such as 5,000. This improves usability by preventing accidental misuse, but it does not protect the server.
Why not? A user can bypass client-side checks by directly entering a URL such as ?N=999999999999. Because the server processes the request regardless of how it was generated, the server-side script must enforce its own constraints on the input it receives.
Server-side input checks can be implemented directly within the server-side script, as shown below:
function (N) {
if (N > 5000) {
N = 0;
}
var out = "";
var iter = 0;
while (iter < N) {
out = out + "G O N A V Y ! ";
iter = iter + 1;
}
return out;
}
In this example, the condition if (N > 5000) enforces a server-side constraint on acceptable input values. Replacing an unacceptable value with a safe one (N = 0;) is an example of input sanitization. Because these checks occur on the server, they are enforced regardless of whether the request originated from a form, a script, or a manually crafted URL.
In summary, while client-side input checks improve usability and efficiency, security depends on the server's ability to independently validate and sanitize all untrusted input. The server must always assume that user input may be malformed, unreasonable, or malicious, and must defend itself accordingly.
rows and cols. Try to craft a URL from that information alone to get a page with the checkerboard pattern.
[click to show answer]
https://courses.cyber.usna.edu/SY110/resources/scripts/checkers.py?rows=10&cols=20
Next, try to create an HTML file with a form that allows the user to enter a number of rows and a number of columns and submits them to the script to get the checkerboard pattern. Use one of the examples from above as a starting point. [click to show answer]
<HTML>
<body>
<form name="checkers"
action="http://courses.cyber.usna.edu/SY110/resources/scripts/checkers.py"
onsubmit="return false;">
Number of rows: <input type="text" name="rows"><br>
Number of columns: <input type="text" name="cols"><br>
<input type="button"
value="Get Checkerboard Pattern"
onclick = "submit();">
</form>
</body>
</HTML>