Created
February 18, 2022 20:41
-
-
Save tacone/ace20190793a6bad667430bbd644e446 to your computer and use it in GitHub Desktop.
Make sure a Url is safe to call from your service
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import hostnameIsPrivate from "hostname-is-private"; | |
import { promisify } from "util"; | |
const isSafeUrl = async (untrustedUrl, protocols = ["http", "https"]) => { | |
try { | |
// will throw error on malfomed url | |
const url = new URL(untrustedUrl); | |
// no protocol, no fun | |
if (!url.protocol) return false; | |
// make sure the protocol is allowed, no file://, ftp:// etc | |
if ( | |
!protocols.filter( | |
(p) => `${p.toLowerCase()}:` == url.protocol.toLowerCase() | |
).length | |
) { | |
return false; | |
} | |
// here it gets interesting, we need to check if the hostname exists, | |
// is reachable, and is not private. We need especially to be sure it | |
// won't resolve to localhost :-)) | |
const notAllowed = await promisify( | |
hostnameIsPrivate.isPrivateIncludingPublicIp | |
)(url.hostname); | |
if (notAllowed) { | |
throw new Error(`Url "${url.hostname} is not allowed`); | |
} | |
return true; | |
} catch (err) { | |
console.error(err); | |
return false; | |
} | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment