Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/azu/url-cheatsheet

URL manipulation cheatsheet for JavaScript
https://github.com/azu/url-cheatsheet

cheatsheet javascript url urlsearchparams

Last synced: 5 days ago
JSON representation

URL manipulation cheatsheet for JavaScript

Awesome Lists containing this project

README

        

# url-cheatsheet

URL manipulation cheatsheet for JavaScript.

## DO NOT: concat url and user input without escape

Please DO NOT concat url and user input without escape

```js
// DO NOT
const name = "";
const url = `https://example.com/user/${name}`;
console.log(url); // => "https://example.com/user/"
```

This code may have directory traversal vulnerability.
You should escape the `name` by `encodeURIComponent`.

```js
// DO
const name = "";
const url = `https://example.com/user/${encodeURIComponent(name)}`;
console.log(url); // => "https://example.com/user/%3Cuser%20input%3E"
```

Addtionaly, You should reject [`.`](https://url.spec.whatwg.org/#single-dot-path-segment) and [`..`](https://url.spec.whatwg.org/#double-dot-path-segment) as a name.
Because `encodeURIComponent("..")` is `..`, it may have directory traversal vulnerability.

```js
// DO
const name = "";
if (name === ".." || name === ".") {
throw new Error("Invalid name");
}
const url = `https://example.com/user/${encodeURIComponent(name)}`;
console.log(url); // => "https://example.com/user/%3Cuser%20input%3E"
```

-
- [Path Traversal | OWASP Foundation](https://owasp.org/www-community/attacks/Path_Traversal)
- [Path Traversal and SSRF - Security, Tech, And Ramblings](https://smarpo.com/posts/path-traversal-and-ssrf/)

## DO NOT: concat parameter and user input without escape

Please DO NOT concat parameter and user input without escape

```js
// DO NOT
const query = "";
const url = `https://example.com?q=${query}`;
console.log(url); // => "https://example.com?q="
```

This example does not consider that `query` includes `&` or `?` that is required to escape.
You should escape the `query` by `encodeURIComponent`.

```js
// DO
const query = "";
const url = `https://example.com?q=${encodeURIComponent(query)}`;
console.log(url); // => "https://example.com?q=%3Cuser%20input%3E"
```

Or, You can use [URLSearchParams()](https://developer.mozilla.org/en-US/docs/Web/API/URLSearchParams/URLSearchParams) that escape each parameters automatically.

- Related: [Client-side HTTP parameter pollution (reflected) - PortSwigger](https://portswigger.net/kb/issues/00501400_client-side-http-parameter-pollution-reflected)

## Base URL + Path

Use [`new URL(pathname, base)`](https://developer.mozilla.org/docs/Web/API/URL/URL).

- keywords: url-join, join path

```js
const base = "https://example.com";
const pathname = "/path/to/page";
const result = new URL(pathname, base);
console.log(result.toString()); // => "https://example.com/path/to/page"
```

If the pathname include user input, you should escape it by `encodeURIComponent`.

```js
const base = "https://example.com/";
const name = "";
const result = new URL(`/user/${encodeURIComponent(name)}`, base);
console.log(result.toString()); // => "https://example.com/user/%3Cuser%20input%3E"
```

Addtionaly, You should reject [`.`](https://url.spec.whatwg.org/#single-dot-path-segment) and [`..`](https://url.spec.whatwg.org/#double-dot-path-segment) as a name.
Because `encodeURIComponent("..")` is `..`, it may have directory traversal vulnerability.

```js
// DO
const base = "https://example.com/";
const name = "";
if (name === ".." || name === ".") {
throw new Error("Invalid name");
}
const result = new URL(`/user/${encodeURIComponent(name)}`, base);
console.log(result.toString()); // => "https://example.com/user/%3Cuser%20input%3E"
```

-
- [Path Traversal | OWASP Foundation](https://owasp.org/www-community/attacks/Path_Traversal)
- [Path Traversal and SSRF - Security, Tech, And Ramblings](https://smarpo.com/posts/path-traversal-and-ssrf/)

## Get parameter from URL

Use [`URL`](https://developer.mozilla.org/docs/Web/API/URL/URL) and [URLSearchParams#get](https://developer.mozilla.org/docs/Web/API/URLSearchParams/get)

```js
const inputURL = "https://example.com/?q=query&page=1";
const url = new URL(inputURL);
const q = url.searchParams.get("q");
console.log(q); // => "query"
```

## Get multiple parameters as array from URL

Use [`URL`](https://developer.mozilla.org/docs/Web/API/URL/URL) and [URLSearchParams#getAll](https://developer.mozilla.org/docs/Web/API/URLSearchParams/getAll)

```js
const inputURL = "https://example.com/?q=query&lang=en_US&lang=ja_JP";
const url = new URL(inputURL);
const langs = url.searchParams.getAll("lang");
console.log(langs); // ["en_US", "ja_JP"]
```

## Add parameters to URL

Use [URLSearchParams](https://developer.mozilla.org/docs/Web/API/URLSearchParams)

```js
const q = "query";
const page = 1;
const base = "https://example.com";
const url = new URL(base);
const params = new URLSearchParams({
q,
page,
});
console.log(url + "?" + params); // => "https://example.com/?q=query&page=1"
```

or

```js
const q = "query";
const page = 1;
const base = "https://example.com";
const url = new URL(base);
url.search = new URLSearchParams({
q,
page,
});
console.log(url.toString()); // => "https://example.com/?q=query&page=1"
```

:memo: `URLSearchParams` escape each parameter automtically.

```js
const q = "";
const page = 1;
const base = "https://example.com";
const url = new URL(base);
url.search = new URLSearchParams({
q,
page,
});
console.log(url.toString()); // => "https://example.com/?q=%3Cuser+input%3E&page=1"
```

## Update parameter of URL

Use [`URL`](https://developer.mozilla.org/docs/Web/API/URL/URL)'s [`searchParams`](https://developer.mozilla.org/docs/Web/API/URL/searchParams) property.

```js
const inputURL = "https://example.com/?q=query&page=1";
const url = new URL(inputURL);
url.searchParams.set("q", "update");
console.log(url.toString()); // => "https://example.com/?q=update&page=1"
```

## Remove parameter from URL

Use [`URL`](https://developer.mozilla.org/docs/Web/API/URL/URL) and [URLSearchParams](https://developer.mozilla.org/docs/Web/API/URLSearchParams)

```js
const inputURL = "https://example.com/?q=query&page=1";
const url = new URL(inputURL);
url.searchParams.delete("q");
console.log(url.toString()); // => "https://example.com/?page=1"
```

## Filter parameters

Allow only `a` and `d` parameters.

- keywords: pick, white list, allow list

```js
const base = "https://example.com/?a=1&b=2&c=3&d=4";
const url = new URL(base);
const allowedParameterNames = ["a", "d"];
url.search = new URLSearchParams(
Array.from(url.searchParams).filter(([key, value]) => {
return allowedParameterNames.includes(key);
})
);
console.log(url.toString()); // => "https://example.com/?a=1&d=4"
```

## Check URL is Absolute-URL

[`new URL(urlString)`](https://developer.mozilla.org/docs/Web/API/URL/URL) throw an error when parsing relative url string.
As a result, you can use `URL` for checking URL is absolute-URL that starts with a schema like `https:`

- Related: [Secure JavaScript URL validation | Snyk](https://snyk.io/blog/secure-javascript-url-validation/)

```js
const isValidURL = (urlString) => {
try {
new URL(urlString); // if `urlString` is invalid, throw an erorr
return true;
} catch {
return false;
}
};
console.log(isValidURL("https://example.com")); // => true
console.log(isValidURL("https/example.com")); // => false
```

## Check URL is HTTP

Check [`URL`](https://developer.mozilla.org/docs/Web/API/URL/URL)'s [`protocol`](https://developer.mozilla.org/docs/Web/API/URL/protocol) property.

```js
const isHttpURL = (urlString) => {
try {
const url = new URL(urlString); // if `urlString` is invalid, throw an erorr
return url.protocol === "http:" || url.protocol === "https:";
} catch {
return false;
}
};
console.log(isHttpURL("http://example.com")); // => true
console.log(isHttpURL("https://example.com")); // => true
console.log(isHttpURL("ftp://example.com")); // => false
console.log(isHttpURL("https/example.com")); // => false
```