diff --git a/1-js/08-prototypes/04-prototype-methods/article.md b/1-js/08-prototypes/04-prototype-methods/article.md index b1e65a66..82a751f9 100644 --- a/1-js/08-prototypes/04-prototype-methods/article.md +++ b/1-js/08-prototypes/04-prototype-methods/article.md @@ -111,7 +111,7 @@ Here the consequences are not terrible. But in other cases the prototype may ind What's worst -- usually developers do not think about such possibility at all. That makes such bugs hard to notice and even turn them into vulnerabilities, especially when JavaScript is used on server-side. -Such thing happens only with `__proto__`. All other properties are "assignable" normally. +Unexpected things also may happen when accessing `toString` property -- that's a function by default, and other built-in properties. How to evade the problem? diff --git a/1-js/plan3.txt b/1-js/plan3.txt index 4d553174..cb954bd3 100644 --- a/1-js/plan3.txt +++ b/1-js/plan3.txt @@ -1,5 +1,9 @@ todo: -intl? -proxy? -eval? +localstorage +fetch +indexdb + +addEventLitener options once passive + +security? xsrf xss csp etc? diff --git a/2-ui/5-data-storage/01-cookie/article.md b/2-ui/5-data-storage/01-cookie/article.md index 56d80eae..ae14d0c2 100644 --- a/2-ui/5-data-storage/01-cookie/article.md +++ b/2-ui/5-data-storage/01-cookie/article.md @@ -1,18 +1,19 @@ # Cookies, document.cookie -Cookies allow to store small pieces of data directly in the browser. They are not part of Javascript, but rather part of HTTP, defined by [RFC 6265](https://tools.ietf.org/html/rfc6265) specification. +Cookies are small strings of data that are stored directly in the browser. They are not a part of Javascript, but rather a part of HTTP protocol, defined by [RFC 6265](https://tools.ietf.org/html/rfc6265) specification. -Most of the time, cookies are set by a webserver, but Javascript can access them too. +Most of the time, cookies are set by a web server. One of the most widespread use of cookies is authentication: -1. Upon sign in, the server sets `Set-Cookie` HTTP-header with a cookie with "session id". -2. The browser stores it. -3. The browser sends it over the net in `Cookie` HTTP-header for every request to the domain that set it. So the server knows who made the request. +1. Upon sign in, the server uses `Set-Cookie` HTTP-header in a response to set a cookie with "session identifier". +2. The browser stores the cookie. +3. Next time when the request is set to the same domain, the browser sends the over the net using `Cookie` HTTP-header. +4. So the server knows who made the request. The browser provides a special accessor `document.cookie` for cookies. -There are many tricky things about cookies and their options, how to set them right. In this chapter we'll cover them in detail. +There are many tricky things about cookies and their options. In this chapter we'll cover them in detail. ## Reading from document.cookie @@ -26,48 +27,55 @@ Assuming you're on a website, it's possible to see the cookies, like this: ```js run // At javascript.info, we use Google Analytics for statistics, -// so there should be some cookies from there. +// so there should be some cookies alert( document.cookie ); // cookie1=value1; cookie2=value2;... ``` -The string consist of `name=value` pairs, delimited by `; `. So, to find a particular cookie, we can split `document.cookie` by `; `, and then find the right key. We can use either a regular expression or array functions to do that. At the end of the chapter you'll find a few functions to manipulate cookies. +The string consist of `name=value` pairs, delimited by `; `. Each one is a separate cookie. + +To find a particular cookie, we can split `document.cookie` by `; `, and then find the right name. We can use either a regular expression or array functions to do that. + +To make things simple, at the end of the chapter you'll find a few functions to manipulate cookies. ## Writing to document.cookie -The `document.cookie` is writable. But it's not a data property, but rather an accessor. +We can write to `document.cookie`. But it's not a data property, it's an accessor. **A write operation to `document.cookie` passes through the browser that updates cookies mentioned in it, but doesn't touch other cookies.** For instance, this call sets a cookie with the name `user` and value `John`: ```js run -document.cookie = "user=John"; -alert(document.cookie); +document.cookie = "user=John"; // update only cookie named 'user' +alert(document.cookie); // show all cookies ``` -If you run it, then probably you'll see multiple cookies. Only the cookie named `user` was altered. +If you run it, then probably you'll see multiple cookies. That's because `document.cookie=` operation does not overwrite all cookies, but only `user`. -Technically, name and value can have any characters, but then they should be escaped using a built-in `encodeURIComponent` function: +Technically, name and value can have any characters, but to keep the formatting valid they should be escaped using a built-in `encodeURIComponent` function: ```js run +// special values, need encoding let name = "<>"; let value = "=" + // encodes the cookie as %3C%3E=%3D document.cookie = encodeURIComponent(name) + '=' + encodeURIComponent(value); + alert(document.cookie); // ...; %3C%3E=%3D ``` ```warn header="Limitations" There are few limitations: -- The `name=value` pair together (after `encodeURIComponent`) should not exceed 4kb. So we can't store anything huge in a cookie. -- The total number of cookies per domain is limited to 30-50, depending on a browser. +- The `name=value` pair, after `encodeURIComponent`, should not exceed 4kb. So we can't store anything huge in a cookie. +- The total number of cookies per domain is limited to 20+, depending on a browser. ``` Cookies have several options, many of them are important and should be set. -The options are listed after `key=value`, delimited by `;`, for instance: +The options are listed after `key=value`, delimited by `;`, like this: ```js run document.cookie = "user=John; path=/; expires=Tue, 19 Jan 2038 03:14:07 GMT" @@ -77,23 +85,21 @@ document.cookie = "user=John; path=/; expires=Tue, 19 Jan 2038 03:14:07 GMT" - **`path=/mypath`** -The url path prefix, where the cookie is accessible. By default, it's the current path. +The url path prefix, where the cookie is accessible. Must be absolute. By default, it's the current path. -If a cookie is set with `path=/mypath`, it's visible at `/mypath` and `/mypath/page`, but not at `/page` or `/mypathpage`. +If a cookie is set with `path=/mypath`, it's visible at `/mypath` and `/mypath/*`, but not at `/page` or `/mypathpage`. Usually, we set `path=/` to make the cookie accessible from all website pages. -Please note: the path must be absolute (start with `/`). - ## domain - **`domain=site.com`** Domain where the cookie is accessible. -By default, cookie is accessible only at the domain that set it. So, if we set a cookie at `site.com`, we won't get it `other.com`. That's natural, as `other.com` is another site. +By default, a cookie is accessible only at the domain that set it. So, if the cookie was set by `site.com`, we won't get it `other.com`. -What's more tricky, we won't get it at a subdomain `forum.site.com`: +...But what's more tricky, we also won't get the cookie at a subdomain `forum.site.com`: ```js // at site.com @@ -107,7 +113,7 @@ alert(document.cookie); // no user It's a safety restriction, to allow us to store sensitive data in cookies. -For subdomains like `forum.site.com` that's possible. If we'd like a subdomain to access the cookie, we should set the `domain` to it. Or, much more common that we'd like any subdomain `*.site.com` to access the cookie, then we should set `domain=site.com`: +...But if we'd like to grant access to subdomains like `forum.site.com`, that's possible. We should explicitly set `domain` option to the root domain: `domain=site.com`: ```js // at site.com, make the cookie accessible on any subdomain: @@ -117,7 +123,7 @@ document.cookie = "user=John; domain=site.com" alert(document.cookie); // with user ``` -For historical reasons, `domain=.site.com` (a dot at the start) also works this way. +For historical reasons, `domain=.site.com` (a dot at the start) also works this way, it might better to add the dot to support very old browsers. ## expires, max-age @@ -138,7 +144,7 @@ date = date.toUTCString(); document.cookie = "user=John; expires=" + date; ``` -If the date is in the past, the cookie will be deleted from the browser. +If we set `expires` to the past, the cookie will be deleted. - **`max-age=3600`** @@ -164,7 +170,7 @@ The cookie should be transferred only over HTTPS. That is, cookies only check the domain, they do not distinguish between the protocols. -With this option, if a cookie is set while `https://site.com`, then it doesn't appear when the same site is accessed by HTTP, as `http://site.com`. So if a cookie has sensitive content that should never be sent over unencrypted HTTP, then the flag can prevent this. +With this option, if a cookie is set by `https://site.com`, then it doesn't appear when the same site is accessed by HTTP, as `http://site.com`. So if a cookie has sensitive content that should never be sent over unencrypted HTTP, then the flag can prevent this. ```js // set the cookie secure (only accessible if over HTTPS) @@ -181,19 +187,19 @@ To understand when it's useful, let's introduce the following attack scenario. Imagine, you are logged into the site `bank.com`. That is: you have an authentication cookie from that site. Your browser sends it to `bank.com` on every request, so that it recognizes you and performs all sensitive financial operations. -Now, while browsing the web in another window, you occasionally come to another site `evil.com`, that has a `