DEV Community

Cover image for Browser Concepts - The one and only guide you need (In progress)

Posted on • Updated on

Browser Concepts - The one and only guide you need (In progress)

"How can our web application run without the browser? That's a good question.. Here are some useful concepts and articles i think a web developer should read regarding browsers. I know i know this is very tedious but trust me some day you will need this :)"

Image description

Table Of Contents

1. Browser Safety

2. Thead and process

3. The mechanism behind browser cache

4. Cookie, Session and LocalStorage

5. Browser same origin policy

6. Garbage Collection in Javascript V8

7. How to Keep user logged in credential

8. What happened when Access-Control-Allow-Origin is * (wild card)

9. Communicate Across Browser Tabs

Other Contents

HTML - The one and only guide you need (in progress)
React Concepts Part.1 - The one and only guide you need
React Concepts Part.2 - The one and only guide you need
CSS Concepts - The one and only guide you need
Web Optimization Concepts - The one and only guide you need
Computer Network Concepts - The one and only guide you need

1. Browser Safety

1.1 Cross Site Scripting attack(XSS)

For more information please refer to this link

What is cross-site scripting (XSS)?

Cross-site scripting (also known as XSS) is a web security vulnerability that allows an attacker to compromise the interactions that users have with a vulnerable application. It usually happens because the website does not filter malicious code, it is mixed with normal code, and the browser has no way to distinguish which scripts are trustworthy, which leads to the execution of malicious code.

How does XSS work?

Cross-site scripting works by manipulating a vulnerable web site so that it returns malicious JavaScript to users if the website does not filter the received data. When the malicious code executes inside a victim's browser, the attacker can fully compromise their interaction with the application.

Three types of XSS attack:

- Reflected cross-site scripting:

Reflected XSS is the simplest variety of cross-site scripting. It arises when an application receives data in an HTTP request and includes that data within the immediate response in an unsafe way.

Here is a simple example of a reflected XSS vulnerability:

<p>Status: All is well.</p>

The application doesn't perform any other processing of the data, so an attacker can easily construct an attack like this:<em>+Bad+stuff+here...+</em>/

<p>Status: <script>/* Bad stuff here... */</script></p>

If the user visits the URL constructed by the attacker, then the attacker's script executes in the user's browser, in the context of that user's session with the application. At that point, the script can carry out any action, and retrieve any data, to which the user has access.

- DOM-based cross-site scripting

DOM-based XSS (also known as DOM XSS) arises when an application contains some client-side JavaScript that processes data from an untrusted source in an unsafe way, usually by writing the data back to the DOM.

In the following example, an application uses some JavaScript to read the value from an input field and write that value to an element within the HTML:

var search = document.getElementById('search').value;
var results = document.getElementById('results');
results.innerHTML = 'You searched for: ' + search;
Enter fullscreen mode Exit fullscreen mode

If the attacker can control the value of the input field, they can easily construct a malicious value that causes their own script to execute:

You searched for: <img src=1 onerror='/* Bad stuff here... */'>

In a typical case, the input field would be populated from part of the HTTP request, such as a URL query string parameter, allowing the attacker to deliver an attack using a malicious URL, in the same manner as reflected XSS.

- Stored cross-site scripting

Stored XSS (also known as persistent or second-order XSS) arises when an application receives data from an untrusted source and includes that data within its later HTTP responses in an unsafe way.

The data in question might be submitted to the application via HTTP requests; for example, comments on a blog post, user nicknames in a chat room, or contact details on a customer order. In other cases, the data might arrive from other untrusted sources; for example, a webmail application displaying messages received over SMTP, a marketing application displaying social media posts, or a network monitoring application displaying packet data from network traffic.

Here is a simple example of a stored XSS vulnerability. A message board application lets users submit messages, which are displayed to other users:

<p>Hello, this is my message!</p>

The application doesn't perform any other processing of the data, so an attacker can easily send a message that attacks other users:

<p><script>/* Bad stuff here... */</script></p>

How to prevent XSS attacks

Preventing cross-site scripting is trivial in some cases but can be much harder depending on the complexity of the application and the ways it handles user-controllable data.

In general, effectively preventing XSS vulnerabilities is likely to involve a combination of the following measures:

  • Filter input on arrival. At the point where user input is received, filter as strictly as possible based on what is expected or valid input.

  • Encode data on output. At the point where user-controllable data is output in HTTP responses, encode the output to prevent it from being interpreted as active content. Depending on the output context, this might require applying combinations of HTML, URL, JavaScript, and CSS encoding.

  • Use appropriate response headers. To prevent XSS in HTTP responses that aren't intended to contain any HTML or JavaScript, you can use the Content-Type and X-Content-Type-Options headers to ensure that browsers interpret the responses in the way you intend.

  • Content Security Policy. As a last line of defense, you can use Content Security Policy (CSP) to reduce the severity of any XSS vulnerabilities that still occur.

1.2 Cross-site request forgery(CSRF)

Refer to this link for more info

What is CSRF?

A CSRF attack refers to a cross-site request forgery attack. The attacker induces a user to enter a third-party website, and then the website sends a cross-site request to the targeted website and bypass the same-origin policy.

The key point of the CSRF attack is to impersonate the user by hijack the cookie as cookie will be carried in the same-origin request and sent to the server.

How to prevent CSRF attack

- Perform same-origin detection: The server should decide whehter the request is allowed based on the request header's origin or referer section.

- Use CSRF token: The server returns a random number Token to the user. When user sends another request, the token will be add to into the request header, and the server verifies this token.

- Set the samesite attribute in Cookie: It will not allow the cookie to be used by third parties, so as to avoid being exploited by attackers.

1.3 What is a man-in-the-middle attack?

Man-in-the-middle attack (MITM) refers to the fact that the attacker establishes a unique connection with both ends of the communication, and exchanges the data they receive, so that both ends of the communication think they are passing through a private connection and a direct conversation with each other, but in fact the entire conversation is completely controlled by the attacker. In a man-in-the-middle attack, the attacker can intercept the two-way communication and insert new content.

The attack process is as follows:

  • The client sends a request to the server, and the request is intercepted by the middleman

  • The server sends the public key to the client

  • The middleman intercepts the public key and keeps it on his own. Then create a fake public key and send it to the client

  • After the client receives the fake public key, it generates an encrypted hash value and sends it to the server.

  • The attacker obtains the encrypted hash value, decrypts it with its own private key to obtain the true key, and at the same time generates a fake encrypted hash value and sends it to the server

  • The server decrypts with the private key to obtain the fake key, and then encrypts the data and transmits it to the client

What may cause front-end security issues?

Other than the above mentioned, we should avoid abusively using iframe. The content inside iframe is provided by the third party. By default, they are not controlled. They can run scripts, Flash plug-ins, pop-up dialog boxes and anything beyond control.

2. Thread and process

2.1 The difference between thread and process

Image description

2.2 Service Worker

read more about service worker

A service worker is a script that runs on a independent thread, it enable applications to control network requests as it is a programmable network proxy which decides how requests from your page are handled., cache those requests to improve performance, and provide offline access to cached content.

Act as the base for advanced features

Service workers provide the starting point for features that make web applications work like native apps. Some of these features are:

  • Notifications API: A way to display and interact with notifications using the operating system's native notification system.

  • Push API: An API that enables your app to subscribe to a push service and receive push messages. Push messages are delivered to a service worker, which can use the information in the message to update the local state or display a notification to the user. Because service workers run independently of the main app, they can receive and display notifications even when the browser is not running.

  • Background Sync API: Lets you defer actions until the user has stable connectivity. This is useful to ensure that whatever the user wants to send is actually sent. This API also allows servers to push periodic updates to the app so the app can update when it's next online

  • Channel Messaging API: Lets web workers and service workers communicate with each other and with the host application. Examples of this API include new content notification and updates that require user interaction.

The service worker life cycle

  • Registration
  • Installation
  • Activation

The service worker life cycle

Web workers

Image description

Web workers are the most general purpose type of worker. Unlike service workers and worklets as we will see below, they do not have a specific use case, other than the feature of being run separately to the main thread. As a result, web workers can be used to offload pretty much any heavy processing from the main thread.

3. The mechanism behind browser cache

The process of browser caching:

  • The browser loads the resource for the first time, the server returns 200, and the browser downloads the resource file from the server, and caches the resource file and response header for comparison and use in the next load;

  • The next time when client request to load resource, the time difference between the current time and the last return of 200 response is first compared. If it does not exceed the max-age set by cache-control, it will hit the cache and load resources locally. If the browser does not support HTTP1.1, use the expires header to determine whether it has expired;

  • If the resource has expired, it means that the cached resource is may no longer valid, and a request with If-None-Match and If-Modified-Since section is sent to the server;

  • After the server receives the request, it first validates whether the requested resource has been modified based on the Etag value. If the Etag value is the same, there is no modification 304 is returned; if E-tag value is inconsistent which means there is a change, and the new resource will be directly returned with a new Etag and status code 200.

  • If the request received by the server does not have an Etag value, it will compare If-Modified-Since with the last modification time of the requested resource. If it has not changed, server will return 304; if they are inconsistent, server will return the response header with new last-modified, resource and return status code 200;

Where are cache stored?

  • Service Worker: Note that if resource is not cached in service worker, it will call the fetch api to look for the cached resource in memory cache.

  • Memory Cache: memory cache will be erased once the tab is closed

  • Disk Cache: reading from disk cache is much slower than memory cache but it can store the resource for longer period.

Why do we need browser cache?

  • For better loading speed of the web page

  • relieve the server's pressure

  • avoid unnecessary network transmission

4. Cookie, Session and LocalStorage

read more about it here

Image description

Cookie attributes: We can set the cookie attributes in Server response header Set-cookie section

  • domain
    Includes the Domain attribute in the cookie to specify the domain for which the cookie is sent.

  • path
    Includes the Path attribute in the cookie to specify the path for which this cookie is sent.

  • secure
    Includes the Secure attribute in the cookie to set whether the cookie is transmitted only over an encrypted connection.

  • httponly
    Includes the HttpOnly attribute in the cookie to set whether the cookie is exposed only through HTTP and HTTPS channels.

  • max-age
    Includes the Max-Age attribute in the cookie to specify the duration of the cookie.

  • expires
    Includes the Expires attribute in the cookie to set the cookie expiration date.

  • custom
    Includes custom attributes in the cookie to specify additional attributes.

  • sameSite
    The SameSite attribute of the Set-Cookie HTTP response header allows you to declare if your cookie should be restricted to a first-party or same-site context.

5. Browser same origin policy

Same-origin policy

The same-origin policy is a critical security mechanism that restricts how a document or script loaded by one origin can interact with a resource from another origin.

It helps isolate potentially malicious documents, reducing possible attack vectors. For example, it prevents a malicious website on the Internet from running JS in a browser to read data from a third-party webmail service (which the user is signed into) or a company intranet (which is protected from direct access by the attacker by not having a public IP address) and relaying that data to the attacker.

6. Garbage Collection in Javascript V8

click here to read more

V8 divides the heap into two parts: young space and old space. When you perform an operations that requires V8 to allocate memory, V8 allocates space in the first portion.

- In the new space,
the memory space is divided into two parts, the From space and the To space. Of these two spaces, one space must be used and the other space is idle. The newly allocated objects will be put into the From space. When the From space is full, the new space Garbage Collector will start. The algorithm will check the surviving objects in the From space and copy them to the To space. If there are inactivated objects, they will be destroyed. When the copy is completed, swap the From space and To space, so that the GC is over.

Once the objects ‘survive’ a few(two to be exact) scavenges in new space, they get promoted to old space, which gets garbage collected in a separate cycle when full.

- In the old space,
When the old space does not have enough space for object being moved from new space or the object in the space exceeds a certain limit. A mark and sweep garbage collection algorithm will be used.

In this stage, all objects in the heap are traversed, and then the live objects are marked. After the marking is completed, all unmarked objects are destroyed. This will cause some performance problems in large memory. To solve this problem, in 2011, V8 switched from the stop-the-world flag to the incremental flag. During the incremental marking, the GC breaks the marking work into smaller modules, allowing the JS application logic to execute for a while between modules, so as not to cause the application to be blocked. But in 2018, GC technology has another major breakthrough, this technology is called concurrent marking. This technology allows GC to scan and mark objects while allowing JS to run.

7. How to Keep user logged in credential

- Browser in-memory scenarios

Token is actually a credential for accessing resources.

Generally, after the user successfully logs in through the user name and password, the server digitally signs the login credentials, and the encrypted character string is used as the token.

Store in the localStorage:
Web storage (localStorage/sessionStorage) can be accessed through the same domain provider through Javascript. This means that any JavaScript running on your website can access the web storage, so it is vulnerable to XSS attacks.

Store in Cookie
We can store it in a cookie and let it be sent automatically on every request, we can specify httponly to prevent it from being read by JavaScript or we can specify secure to ensure that the token is only transmitted under HTTPS to prevent being attacked by XSS, but the disadvantage is that it cannot cross domains and vulnerable to CSRF attacks.

Recommended Solution
Auth0 recommends storing tokens in browser memory as the most secure option. Using Web Workers to handle the transmission and storage of tokens is the best way to protect the tokens, as Web Workers run in a separate global scope than the rest of the application. Use Auth0 SPA SDK whose default storage option is in-memory storage leveraging Web Workers.

8. What happened when Access-Control-Allow-Origin is * (wild card)

When Access-Control-Allow-Origin is *. The client side will not be able to carry the cookies in request even setting XMLHttpRequest's withCredentials: true.

The withCredentials flag of XMLHttpRequest is set to true in order for the client to send cookies to the server. Access-Control-Allow-Credentials: true in the response is for the client to be able to receive cookies. Without these settings, the browser will not return the response content to the sender of the request.

Therefore, for the client to carry cookies to the server, three conditions are required:

  1. Access-Control-Allow-Origin cannot be *, it should be a specific domain name

  2. Server Access-Control-Allow-Credentials should be true

  3. withCredentials=true of the client XMLHttpRequest

9. Communicate Across Browser Tabs

click here to read more

1. Local Storage Events

window.localStorage.setItem("loggedIn", "true");

The other Tabs which listen to the event will receive it, as shown below.

window.addEventListener('storage', (event) => {
 if (event.storageArea != localStorage) return;
 if (event.key === 'loggedIn') {
   // Do something with event.newValue
Enter fullscreen mode Exit fullscreen mode
  • This event is not triggered for the Tab, which performs the storage set action.
  • For a large chunk of data, this approach has adverse effects since LocalStorage is synchronous. And hence can block the main UI thread

2. Broadcast Channel API

The Broadcast Channel API allows communication between Tabs, Windows, Frames, Iframes, and Web Workers. One Tab can create and post to a channel as follows.

const channel = new BroadcastChannel('app-data');

And other Tabs can listen to channel as follows.

const channel = new BroadcastChannel('app-data');
channel.addEventListener ('message', (event) => {
Enter fullscreen mode Exit fullscreen mode

3. Service Worker Post Message

Using Service Workers, you can send a message like shown below.

 broadcast: data
Enter fullscreen mode Exit fullscreen mode

And in the receiving Worker in the other Browser Tab can listen to the event.

addEventListener('message', async (event) => {
 if ('boadcast' in ) {
  const allClients = await clients.matchAll();
  for (const client of allClients) {
Enter fullscreen mode Exit fullscreen mode

This method gives more control and is a reliable way of passing messages.

4. Window Post Message

One of the traditional ways of communicating across Browser Tabs, Popups, and Iframes is Window.postMessage() method. You can send the message as follows.

targetWindow.postMessage(message, targetOrigin)

And the target window can listen to the events, as shown below.

window.addEventListener("message", (event) => {
  if (event.origin !== "http://localhost:8080")
  // Do something
}, false);
Enter fullscreen mode Exit fullscreen mode

One advantage of this method over the others is the support for cross-origin communication is possible.

When we want to communicate between two tabs from different origin, we can use iframe as a bridge, post message to the iframe and listen to the message received from iframe.

Discussion (0)