HTTP communication
Overview
Overview
Request
Overview
Request
Response
Request
GET / HTTP/1.1
Host: www.google.fr
Accept: text/html
POST /messages HTTP/1.1
Host: www.example.com
Content-Type: application/json
Cookie: sessionid=aa03x;
Content-Length: 79
{ "from": "Marvin", "to": "Arthur",
"content": "Did I say something wrong?" }
Request
POST /messages HTTP/1.1
Host: www.example.com
Content-Type: application/json
Cookie: sessionid=aa03x;
Content-Length: 79
{ "from": "Marvin", "to": "Arthur",
"content": "Did I say something wrong?" }
HTTP verbs
GET: read and do not change
state
POST: change the state
GET / HTTP/1.1
Host: www.google.fr
Accept: text/html
Request
POST /messages HTTP/1.1
Host: www.example.com
Content-Type: application/json
Cookie: sessionid=aa03x;
Content-Length: 79
{ "from": "Marvin", "to": "Arthur",
"content": "Did I say something wrong?" }
HTTP verbs
GET: read and do not change
state
POST: change the state
Other verbs: HEAD, PUT, OPTIONS, DELETE, ...
Semantic is a convention
GET / HTTP/1.1
Host: www.google.fr
Accept: text/html
Request
POST /messages HTTP/1.1
Host: www.example.com
Content-Type: application/json
Cookie: sessionid=aa03x;
Content-Length: 79
{ "from": "Marvin", "to": "Arthur",
"content": "Did I say something wrong?" }
Path
String processed by server
GET / HTTP/1.1
Host: www.google.fr
Accept: text/html
Request
POST /messages HTTP/1.1
Host: www.example.com
Content-Type: application/json
Cookie: sessionid=aa03x;
Content-Length: 79
{ "from": "Marvin", "to": "Arthur",
"content": "Did I say something wrong?" }
Path
String processed by server
Encoding convention:
space -> %20
GET / HTTP/1.1
Host: www.google.fr
Accept: text/html
Request
POST /messages HTTP/1.1
Host: www.example.com
Content-Type: application/json
Cookie: sessionid=aa03x;
Content-Length: 79
{ "from": "Marvin", "to": "Arthur",
"content": "Did I say something wrong?" }
Protocol
GET / HTTP/1.1
Host: www.google.fr
Accept: text/html
Request
POST /messages HTTP/1.1
Host: www.example.com
Content-Type: application/json
Cookie: sessionid=aa03x;
Content-Length: 79
{ "from": "Marvin", "to": "Arthur",
"content": "Did I say something wrong?" }
Protocol
HTTP/1.1
ASCII (text) based
HTTP/2.0
Binary based
Reduce latency
Backward compatibility
GET / HTTP/1.1
Host: www.google.fr
Accept: text/html
Request
POST /messages HTTP/1.1
Host: www.example.com
Content-Type: application/json
Cookie: sessionid=aa03x;
Content-Length: 79
{ "from": "Marvin", "to": "Arthur",
"content": "Did I say something wrong?" }
Headers
GET / HTTP/1.1
Host: www.google.fr
Accept: text/html
Request
POST /messages HTTP/1.1
Host: www.example.com
Content-Type: application/json
Cookie: sessionid=aa03x;
Content-Length: 79
{ "from": "Marvin", "to": "Arthur",
"content": "Did I say something wrong?" }
Headers
Host is mandatory for all
requests
GET / HTTP/1.1
Host: www.google.fr
Accept: text/html
Request
POST /messages HTTP/1.1
Host: www.example.com
Content-Type: application/json
Cookie: sessionid=aa03x;
Content-Length: 79
{ "from": "Marvin", "to": "Arthur",
"content": "Did I say something wrong?" }
Accept
format in which we
ASK the data
application/json
text/xml
text/html
...
GET / HTTP/1.1
Host: www.google.fr
Accept: text/html
Request
POST /messages HTTP/1.1
Host: www.example.com
Content-Type: application/json
Cookie: sessionid=aa03x;
Content-Length: 79
{ "from": "Marvin", "to": "Arthur",
"content": "Did I say something wrong?" }
Content-Type
format in which we
SEND the data
application/json
text/xml
multipart/form-data
...
GET / HTTP/1.1
Host: www.google.fr
Accept: text/html
Request
POST /messages HTTP/1.1
Host: www.example.com
Content-Type: application/json
Cookie: sessionid=aa03x;
Content-Length: 79
{ "from": "Marvin", "to": "Arthur",
"content": "Did I say something wrong?" }
Cookie
A string the server
previously sent to us
GET / HTTP/1.1
Host: www.google.fr
Accept: text/html
Request
POST /messages HTTP/1.1
Host: www.example.com
Content-Type: application/json
Cookie: sessionid=aa03x;
Content-Length: 79
{ "from": "Marvin", "to": "Arthur",
"content": "Did I say something wrong?" }
Content-Length
Mandatory for POST and
PUT request.
GET / HTTP/1.1
Host: www.google.fr
Accept: text/html
Request
POST /messages HTTP/1.1
Host: www.example.com
Content-Type: application/json
Cookie: sessionid=aa03x;
Content-Length: 79
{ "from": "Marvin", "to": "Arthur",
"content": "Did I say something wrong?" }
Body: the data we send to the server -- optional -- after a blank line.
Raw string
JSON
XML
... whatever the server
accepts
GET / HTTP/1.1
Host: www.google.fr
Accept: text/html
A lot of custom headers
A LOT of custom headers
Overview
Request
Response
Response
HTTP/1.1 200 OK
Date: Tue, 24 Jan 2012 18:34:40 GMT
Server: Apache/2.2.21 (Debian)
Content-Length: 21
Content-Type: text/html
Set-Cookie: sessionid=jkWXBR;
<h1>Hello world!</h1>
HTTP/1.1 400 BAD_REQUEST
Server: Apache/2.2.21 (Debian)
Content-Length: 21
Content-Type: application/json
{ "error": "email is required" }
Response
HTTP/1.1 200 OK
Date: Tue, 24 Jan 2012 18:34:40 GMT
Server: Apache/2.2.21 (Debian)
Content-Length: 21
Content-Type: text/html
Set-Cookie: sessionid=jkWXBR;
<h1>Hello world!</h1>
HTTP/1.1 400 BAD_REQUEST
Server: Apache/2.2.21 (Debian)
Content-Length: 21
Content-Type: application/json
{ "error": "email is required" }
Protocol:
HTTP/1.1
HTTP/2.0
Response
HTTP/1.1 200 OK
Date: Tue, 24 Jan 2012 18:34:40 GMT
Server: Apache/2.2.21 (Debian)
Content-Length: 21
Content-Type: text/html
Set-Cookie: sessionid=jkWXBR;
<h1>Hello world!</h1>
HTTP/1.1 400 BAD_REQUEST
Server: Apache/2.2.21 (Debian)
Content-Length: 21
Content-Type: application/json
{ "error": "email is required" }
Status code
200 OK
201 CREATED
301 MOVE
PERMANENTLY
307 TEMPORARY
REDIRECT
400 BAD REQUEST
403 FORBIDDEN
404 NOT FOUND
418 I'M A TEAPOT
500 SERVER ERROR
503 SERVICE
UNAVAILABLE
Response
HTTP/1.1 200 OK
Date: Tue, 24 Jan 2012 18:34:40 GMT
Server: Apache/2.2.21 (Debian)
Content-Length: 21
Content-Type: text/html
Set-Cookie: sessionid=jkWXBR;
<h1>Hello world!</h1>
HTTP/1.1 400 BAD_REQUEST
Server: Apache/2.2.21 (Debian)
Content-Length: 21
Content-Type: application/json
{ "error": "email is required" }
Headers.
What the server wants to tell to us.
Response
HTTP/1.1 200 OK
Date: Tue, 24 Jan 2012 18:34:40 GMT
Server: Apache/2.2.21 (Debian)
Content-Length: 21
Content-Type: text/html
Set-Cookie: sessionid=jkWXBR;
<h1>Hello world!</h1>
HTTP/1.1 400 BAD_REQUEST
Server: Apache/2.2.21 (Debian)
Content-Length: 21
Content-Type: application/json
{ "error": "email is required" }
Content-Type: the actual format in which the server send the data.
Can be different from the request's Accept header.
Response
HTTP/1.1 200 OK
Date: Tue, 24 Jan 2012 18:34:40 GMT
Server: Apache/2.2.21 (Debian)
Content-Length: 21
Content-Type: text/html
Set-Cookie: sessionid=jkWXBR;
<h1>Hello world!</h1>
HTTP/1.1 400 BAD_REQUEST
Server: Apache/2.2.21 (Debian)
Content-Length: 21
Content-Type: application/json
{ "error": "email is required" }
Set-Cookie: the server
asks us to keep in memory a string
This string should be send back to the server at the next request.
Response
HTTP/1.1 200 OK
Date: Tue, 24 Jan 2012 18:34:40 GMT
Server: Apache/2.2.21 (Debian)
Content-Length: 21
Content-Type: text/html
Set-Cookie: sessionid=jkWXBR;
<h1>Hello world!</h1>
HTTP/1.1 400 BAD_REQUEST
Server: Apache/2.2.21 (Debian)
Content-Length: 21
Content-Type: application/json
{ "error": "email is required" }
Body -- optional -- after a blank line.
The actual payload of the response.
Overview
Request
Response
Only conventions!
Hands on!
Open the developer tools, select "Network" tab.
Enter the (exact) url https://wikipedia.org an observe the requests/responses!
Cookies: sid=aJ5Ke5;__utma=142543.221.52;__utmz=521441
http://my-site.com
Cookies: ssid=5aKa47ec;alert=false;v=0.19
http://example.com
Cookies: __utma=98465.316542213.65;__utmz=152357.6368432
http://bingo.org
are used to identify users
Cookies: sid=aJ5Ke5;__utma=142543.221.52;__utmz=521441
http://my-site.com
Cookies: ssid=5aKa47ec;alert=false;v=0.19
http://example.com
Cookies: __utma=98465.316542213.65;__utmz=152357.6368432
http://bingo.org
are isolated
Cookies: sid=aJ5Ke5;__utma=142543.221.52;__utmz=521441
http://my-site.com
Cookies: ssid=5aKa47ec;alert=false;v=0.19
http://example.com
Cookies: __utma=98465.316542213.65;__utmz=152357.6368432
http://bingo.org
Hands on!
Open the developer tools, select "Storage" tab.
Browse in multiple websites and observe the cookies!
Security
Plain Text : Every body can intercept...
Plain Text : ... or even modify the messages
Solution: HTTPS
"S" for "Secure"
https://en.wikipedia.org/wiki/HTTPS
Issue requests
Issue GET requests
GET /fr/ HTTP/1.1
Host: www.mozilla.org
Issue GET requests
<form action="/search">
<input name="q" type="text">
<input name="num" type="number">
<input type="submit">
</form>
Issue GET requests
<form action="/search">
<input name="q" type="text">
<input name="num" type="number">
<input type="submit">
</form>
GET /search?q=Marvin&num=3 HTTP/1.1
Host: www.example.com
Submit
Issue GET requests
<form action="/search" method="GET">
<input name="q" type="text">
<input name="num" type="number">
<input type="submit">
</form>
GET /search?q=Marvin&num=3 HTTP/1.1
Host: www.example.com
Default method
Issue GET requests
Issue POST requests
<form action="/message" method="POST">
<input name="to" type="text">
<input name="content" type="text">
<input type="submit">
</form>
Issue POST requests
<form action="/message" method="POST">
<input name="to" type="text">
<input name="content" type="text">
<input type="submit">
</form>
Issue POST requests
<form action="/message" method="POST">
<input name="to" type="text">
<input name="content" type="text">
<input type="submit">
</form>
POST /message HTTP/1.1
Host: www.example.com
Content-Type: application/x-www-form-urlencoded
Content-Length: 52
to=Ford&content=Did%20I%20say%20something%20wrong%3F
Submit
Issue POST requests
<form action="/message" method="POST">
<input name="to" type="text">
<input name="content" type="text">
<input type="submit">
</form>
POST /message HTTP/1.1
Host: www.example.com
Content-Type: application/x-www-form-urlencoded
Content-Length: 52
to=Ford&content=Did%20I%20say%20something%20wrong%3F
Urlencoded: "Did I say something wrong?"
Answer a request
Web frameworks handle details
from flask import Flask
app = Flask(__name__)
@app.route("/")
def hello():
return "Hello World!"
if __name__ == '__main__':
app.run()
Web frameworks handle details
from flask import Flask
app = Flask(__name__)
@app.route("/")
def hello():
return "Hello World!"
if __name__ == '__main__':
app.run()
The user sent the request:
GET / HTTP/1.1
Host: www.example.com
Web frameworks handle details
from flask import Flask
app = Flask(__name__)
@app.route("/")
def hello():
return "Hello World!"
if __name__ == '__main__':
app.run()
The server answers:
HTTP/1.1 200 OK
Content-Length: 12
Content-Type: text/html
Hello world!
@app.route("/", methods=["GET"])
def hello():
name = request.args['name']
return "Hello " + name + "!"
Get the arguments!
@app.route("/", methods=["GET"])
def hello():
name = request.args['name']
return "Hello " + name + "!"
The user sends the request:
GET /?name=Arthur%20Dent HTTP/1.1
Host: www.example.com
Get the arguments!
@app.route("/", methods=["GET"])
def hello():
name = request.args['name']
return "Hello " + name + "!"
The user sends the request:
GET /?name=Arthur%20Dent HTTP/1.1
Host: www.example.com
Get the arguments!
The server answers:
HTTP/1.1 200 OK
Content-Length: 18
Content-Type: text/html
Hello Arthur Dent!
@app.route("/", methods=["GET"])
def hello():
name = request.args['name']
return "Hello " + name + "!"
The user send the request:
GET /?name=Arthur%20Dent HTTP/1.1
Host: www.example.com
Get the arguments!
The server answers:
HTTP/1.1 200 OK
Content-Length: 18
Content-Type: text/html
Hello Arthur Dent!
Never trust user input!
<script>
id = get_session_id();
send_to_Ford(id);
</script>
<script>
id = get_session_id();
send_to_Ford(id);
</script>
1. URL-encode
https://attacked-site/
?name=%3Cscript%3E%0A%20
%20id%20%3D%20get_session
_id%28%29%3B%20%0A%20%20s
end_to_Ford%28id%29%3B%0A
%3C%2Fscript%3E
<script>
id = get_session_id();
send_to_Ford(id);
</script>
1. URL-encode
<p>Hey folks!</p>
<p>Check out my
<a href="...">
new website!</a>
</p>
2. Send this email
https://attacked-site/
?name=%3Cscript%3E%0A%20
%20id%20%3D%20get_session
_id%28%29%3B%20%0A%20%20s
end_to_Ford%28id%29%3B%0A
%3C%2Fscript%3E
1. sends the link via emails or publishes it on a website
1. sends the link via emails or publishes it on a website
2. clicks on the link
1. sends the link via emails or publishes it on a website
2. clicks on the link
3. Generates the malicious HTML code
1. sends the link via emails or publishes it on a website
2. clicks on the link
3. Generates the malicious HTML code
4. sends back the HTML code
1. sends the link via emails or publishes it on a website
2. clicks on the link
3. Generates the malicious HTML code
4. sends back the HTML code
5. runs the code and sends data
Ford has stolen your identity
@app.route("/", methods=["GET"])
def hello():
name = request.args['name']
return "Hello " + name + "!"
The user sends the request:
GET /?name=Arthur%20Dent HTTP/1.1
Host: www.example.com
Get the arguments!
The server answers:
HTTP/1.1 200 OK
Content-Length: 18
Content-Type: text/html
Hello Arthur Dent!
@app.route("/", methods=["POST"])
def hello():
name = request.form['name']
return "Hello " + name + "!"
The user sends the request:
POST / HTTP/1.1
Host: www.example.com
Content-Type: application/x-www-form-urlencoded
Content-Length: 18
name=Arthur%20Dent
Get the arguments from POST!
@app.route("/", methods=["POST"])
def hello():
name = request.form['name']
return "Hello " + name + "!"
The user sends the request:
POST / HTTP/1.1
Host: www.example.com
Content-Type: application/x-www-form-urlencoded
Content-Length: 18
name=Arthur%20Dent
Get the arguments from POST!
@app.route("/", methods=["POST"])
def hello():
name = request.form['name']
return "Hello " + name + "!"
The user sends the request:
POST / HTTP/1.1
Host: www.example.com
Content-Type: application/x-www-form-urlencoded
Content-Length: 18
name=Arthur%20Dent
Get the arguments from POST!
Use templates!
Use templates!
@app.route("/", methods=["GET"])
def hello():
name = request.args['name']
return "Hello " + name + "!"
Use templates!
@app.route("/", methods=["GET"])
def hello():
name = request.args['name']
return render_template("hi.html", name=name)
server.py
Use templates!
@app.route("/", methods=["GET"])
def hello():
name = request.args['name']
return render_template("hi.html", name=name)
server.py
<p>Hello {{ name }}</p>
hi.html
Use templates!
@app.route("/", methods=["GET"])
def hello():
name = request.args['name']
return render_template("hi.html", name=name)
server.py
<p>Hello {{ name }}</p>
hi.html
<p>Hello Arthur</p>
sent to the browser
<p>Hello {{ name }}</p>
(almost) any Python expression
Jinja syntax
<p>Hello {{ name }}</p>
(almost) any Python expression
<p>Hello {{ name.title() }}</p>
Jinja syntax
<p>Hello {{ name }}</p>
(almost) any Python expression
<p>Hello {{ name.title() }}</p>
with name: "arthur dent"
<p>Hello Arthur Dent</p>
Jinja syntax
<p>Hello {{ name }}</p>
escaped by default
Jinja syntax
with name: "Arthur <script>alert('...')</script>"
<p>Hello {{ name }}</p>
escaped by default
Jinja syntax
with name: "Arthur <script>alert('...')</script>"
<p>Hello
<script>alert('...')</script>
</p>
sent to the browser
<p>Hello {{ name }}</p>
escaped by default
Jinja syntax
with name: "Arthur <script>alert('...')</script>"
<p>Hello
<script>alert('...')</script>
</p>
sent to the browser
displayed by the browser
{% if likes_count > 100 %}
<p>Hey, you are very popular,
you are liked by {{ likes_count }}
people
</p>
{% elif likes_count > 10 %}
<p>You are liked by
{{ likes_count }} people
</p>
{% else %}
<p>Only
{{ likes_count }} people
like you... It is so sad...
</p>
{% endif %}
If branching
<ul>
{% for name in names %}
<li>{{ name }}</li>
{% end %}
</ul>
For loops
<ul>
{% for name in names %}
<li>{{ name }}</li>
{% end %}
</ul>
For loops
with users: [ "Arthur", "Ford", "Marvin"]
<ul>
<li>Arthur</li>
<li>Ford</li>
<li>Marvin</li>
</ul>
<!DOCTYPE html>
<html>
<head>
<title>{% block title %}{% endblock %}</title>
</head>
<body>
<h1>Main heading</h1>
{% block content %}{% endblock %}
</body>
</html>
Inheritance
base.html
<!DOCTYPE html>
<html>
<head>
<title>{% block title %}{% endblock %}</title>
</head>
<body>
<h1>Main heading</h1>
{% block content %}{% endblock %}
</body>
</html>
Inheritance
base.html
defined by the programmer
Inheritance
{% extends "base.html" %}
{% block title %}Welcome{% endblock %}
{% block content %}
<p>
Hello {{ name }}
</p>
{% endblock %}
hello.html
Inheritance
{% extends "base.html" %}
{% block title %}Login{% endblock %}
{% block content %}
<form>
<input name="login" />
<input name="password" type="password" />
<input type="submit" />
</form>
{% endblock %}
login.html
Hackathon Elm : October 5, 9.00 - 19.00
HTTP Communication - TWTS 03
By sebbes
HTTP Communication - TWTS 03
- 931