open, opens the request, parameters:method – method to be used (e.g. GET, PUT,
POST),url – url of the resource,asynch – true to make asynchronous call,user, pass – credentials for
authentication.onReadyStateChange – JavaScript function object, it is called when
readyState changes (uninitialized, loading, loaded, interactive, completed).
send, abort – sends or aborts the request
(for asynchronous calls)status, statusText – HTTP status code and a
corresponding text.responseText, responseXML – response as text or
as a DOM document (if possible).onload – event listener to support server push.fetch method to fetch resources asynchronouslyRequest – represents a request to be madeResponse – represents a response to a requestHeaders – represents response/request headers
async function logMovies() {
const response = await fetch("http://example.com/movies.json");
const movies = await response.json();
console.log(movies);
}
fetch function is available in global windowpath and returns Promise
fetch('https://api.github.com/users/tomvit')
.then(response => response.json())
.then(data => console.log(data))
.catch(error => console.error('Error:', error));
no-cors requestsrc to
img
fetch('https://google.com', {
mode: 'no-cors',
}).then(function (response) {
console.log(response.type);
});
responseText would be loaded into memory.SameSite cookies, CSP, CORS, Trusted Types
fetch/XHR; History API routingapi.* subdomain or separate originOPTIONS) become commonSameSite, tokens, Origin check)
state/nonce validationscript-src), SRI, and limiting
connect-src
Authorization: Bearer ...)Secure: only over HTTPSHttpOnly: not readable by JavaScriptSameSite: limits cross-site cookie sendingSameSite=Lax (reduces CSRF via cross-site
navigation)
SameSite=None, legacy apps, subdomain
issues, OAuth flows<form method="POST"> submitSameSite=Lax (default) or Strict where possibleNone; Secure when requiredOrigin header for state-changing requests (often better than
Referer)
<form action="https://bank.com/transfer" method="POST"> <input type="hidden" name="to" value="mallory" /> <input type="hidden" name="amount" value="50000" /> </form> <script>document.forms[0].submit()</script>
bank.com on this cross-site POSTOrigin)<form>)SameSite cookies and Origin checksTT in cookie csrf=TT in csrf_token (form field)
or X-CSRF-Token (header)Cookie[csrf] == token_in_body_or_headerSecure and HTTPS; combine with SameSite and
Origin checks
https://app.com)
HttpOnly, but attackers can still:fetch)localStorage<meta>)<script>, inline
handlers)script-src: where scripts can come from; can require 'nonce-...' /
hashesconnect-src: where JS can send requests (fetch/XHR/WebSocket)img-src, style-src, font-src: resource allowlists
object-src 'none': disable plugin contentbase-uri: restrict <base> tag abuseframe-ancestors: who may embed the page (clickjacking defense)selfContent-Security-Policy: default-src 'self'; script-src 'self' 'nonce-ABC123'; connect-src 'self' https://api.example.com; object-src 'none'; base-uri 'self'; frame-ancestors 'none'
<script nonce="ABC123">
// allowed inline script
window.appBoot();
</script>
<script>
// blocked inline script (missing nonce)
alert('XSS');
</script>
// URL: https://app.com/welcome?name=<img src=x onerror=alert(1)>
const params = new URLSearchParams(location.search);
const name = params.get("name");
// Dangerous sink:
document.querySelector("#welcome").innerHTML = "Hi " + name;
textContent instead of innerHTML
There is a great event happening at
http://someurl.com/@"onmouseover="alert('test xss')"/
<a> element
There is a great event happening at
<a href="http://someurl.com/@"onmouseover="alert('test xss')"
target="_blank">http://someurl.com/@"onmouseover=
"alert('test xss')"/</a>
<iframe> and
overlay it under a decoy button
<div id="decoy">
Click to claim your prize
<button>Claim</button>
</div>
<!-- Invisible/transparent iframe aligned so victim's click hits "Confirm" -->
<iframe id="targetFrame" src="https://bank.com/transfer/confirm"></iframe>
<style>
#targetFrame {
position: absolute;
top: 120px; left: 90px; /* align target button under decoy */
width: 1000px; height: 800px;
opacity: 0.01; border: 0; /* nearly invisible */
}
#decoy { position: relative; z-index: 2; }
</style>
Content-Security-Policy: frame-ancestors 'none' (or allowlist trusted
embedders)SameSite, CSRF tokens, Origin checksOrigin – identifies the origin of the requestAccess-Control-Allow-Origin – defines who can access the resource
OPTIONS methodAccess-Control-Max-Age{"name" : "tomas", "age" : 18, "student" : false, "car" : null}
[ "prague", "innsbruck", 45 ]
[ { "name" : "tomas", "age" : 18 },
{ "name" : "peter", "age" : 19 } ]
{ "cities" : ["prague", "innsbruck"],
"states" : ["CZ", "AT"] }
// data needs to be assigned
var data = { "people" : ["tomas", "peter", "alice", "jana"] };
// go through the list of people
for (var i = 0; i < data.people.length; i++) {
var man = data.people[i];
// ... do something with this man
}
GET http://pipes.yahoo.com/pipes/pipe.run?_id=638c670c40c97b62&_render=json
{"count":1,"value":
{"title":"Web 2.0 announcements",
"description":"Pipes Output",
"link":"http:\/\/pipes.yahoo.com\/pipes\/pipe.info...",
"pubDate":"Mon, 07 Mar 2011 18:27:20 +0000",
"generator":"..."
...
}
}
http://someurl.org/json_data returns
{ "people" : ["tomas", "peter", "alice", "jana"] }
then the resource athttp://someurl.org/json_data?_callback=loadData returns
loadData({ "people" : ["tomas", "peter", "alice", "jana"] });
GET, nothing else works obviously<script> element<script>
into the current document. This will download JSON data and triggers the script.
var TWITTER_URL = "http://api.twitter.com/1/statuses/user_timeline.json?" +
"&screen_name=web2e&count=100&callback=loadData";
// this needs to be loaded in window.onload
// after all document has finished loading...
function insertData() {
var se = document.createElement('script');
se.setAttribute("type","text/javascript");
se.setAttribute("src", TWITTER_URL);
document.getElementsByTagName("head")[0].appendChild(se);
// And data will be loaded when loadDta callback fires...
}
// loads the data when they arrive
function loadData(data) {
// we need to know the the structure of JSON data that is returned
// and code it here accordingly
for (var i = 0; i < data.length; i++) {
data[i].created_at // contains date the tweet was created
data[i].text // contains the tweet
}
}