1+ // eslint-disable-next-line max-classes-per-file
12const http = require ( 'http' )
23const https = require ( 'https' )
34const { URL } = require ( 'url' )
45const dns = require ( 'dns' )
5- const ipAddress = require ( 'ip-address' )
66const request = require ( 'request' )
7+ const ipaddr = require ( 'ipaddr.js' )
8+
79const logger = require ( '../logger' )
810
911const FORBIDDEN_IP_ADDRESS = 'Forbidden IP address'
1012
11- function isIPAddress ( address ) {
12- const addressAsV6 = new ipAddress . Address6 ( address )
13- const addressAsV4 = new ipAddress . Address4 ( address )
14- return addressAsV6 . isValid ( ) || addressAsV4 . isValid ( )
15- }
16-
17- /* eslint-disable max-len */
18- /**
19- * Determine if a IP address provided is a private one.
20- * Return TRUE if it's the case, FALSE otherwise.
21- * Excerpt from:
22- * https://cheatsheetseries.owasp.org/cheatsheets/Server_Side_Request_Forgery_Prevention_Cheat_Sheet.html#case-2---application-can-send-requests-to-any-external-ip-address-or-domain-name
23- *
24- * @param {string } ipAddress the ip address to validate
25- * @returns {boolean }
26- */
27- /* eslint-enable max-len */
28- function isPrivateIP ( ipAddress ) {
29- let isPrivate = false
30- // Build the list of IP prefix for V4 and V6 addresses
31- const ipPrefix = [ ]
32- // Add prefix for loopback addresses
33- ipPrefix . push ( '127.' )
34- ipPrefix . push ( '0.' )
35- // Add IP V4 prefix for private addresses
36- // See https://en.wikipedia.org/wiki/Private_network
37- ipPrefix . push ( '10.' )
38- ipPrefix . push ( '172.16.' )
39- ipPrefix . push ( '172.17.' )
40- ipPrefix . push ( '172.18.' )
41- ipPrefix . push ( '172.19.' )
42- ipPrefix . push ( '172.20.' )
43- ipPrefix . push ( '172.21.' )
44- ipPrefix . push ( '172.22.' )
45- ipPrefix . push ( '172.23.' )
46- ipPrefix . push ( '172.24.' )
47- ipPrefix . push ( '172.25.' )
48- ipPrefix . push ( '172.26.' )
49- ipPrefix . push ( '172.27.' )
50- ipPrefix . push ( '172.28.' )
51- ipPrefix . push ( '172.29.' )
52- ipPrefix . push ( '172.30.' )
53- ipPrefix . push ( '172.31.' )
54- ipPrefix . push ( '192.168.' )
55- ipPrefix . push ( '169.254.' )
56- // Add IP V6 prefix for private addresses
57- // See https://en.wikipedia.org/wiki/Unique_local_address
58- // See https://en.wikipedia.org/wiki/Private_network
59- // See https://simpledns.com/private-ipv6
60- ipPrefix . push ( 'fc' )
61- ipPrefix . push ( 'fd' )
62- ipPrefix . push ( 'fe' )
63- ipPrefix . push ( 'ff' )
64- ipPrefix . push ( '::1' )
65- // Verify the provided IP address
66- // Remove whitespace characters from the beginning/end of the string
67- // and convert it to lower case
68- // Lower case is for preventing any IPV6 case bypass using mixed case
69- // depending on the source used to get the IP address
70- const ipToVerify = ipAddress . trim ( ) . toLowerCase ( )
71- // Perform the check against the list of prefix
72- for ( const prefix of ipPrefix ) {
73- if ( ipToVerify . startsWith ( prefix ) ) {
74- isPrivate = true
75- break
76- }
77- }
78-
79- return isPrivate
80- }
13+ // Example scary IPs that should return false (ipv6-to-ipv4 mapped):
14+ // ::FFFF:127.0.0.1
15+ // ::ffff:7f00:1
16+ const isDisallowedIP = ( ipAddress ) => ipaddr . parse ( ipAddress ) . range ( ) !== 'unicast'
8117
8218module . exports . FORBIDDEN_IP_ADDRESS = FORBIDDEN_IP_ADDRESS
8319
@@ -115,7 +51,7 @@ function dnsLookup (hostname, options, callback) {
11551
11652 const toValidate = Array . isArray ( addresses ) ? addresses : [ { address : addresses } ]
11753 for ( const record of toValidate ) {
118- if ( isPrivateIP ( record . address ) ) {
54+ if ( isDisallowedIP ( record . address ) ) {
11955 callback ( new Error ( FORBIDDEN_IP_ADDRESS ) , addresses , maybeFamily )
12056 return
12157 }
@@ -127,7 +63,7 @@ function dnsLookup (hostname, options, callback) {
12763
12864class HttpAgent extends http . Agent {
12965 createConnection ( options , callback ) {
130- if ( isIPAddress ( options . host ) && isPrivateIP ( options . host ) ) {
66+ if ( ipaddr . isValid ( options . host ) && isDisallowedIP ( options . host ) ) {
13167 callback ( new Error ( FORBIDDEN_IP_ADDRESS ) )
13268 return undefined
13369 }
@@ -138,7 +74,7 @@ class HttpAgent extends http.Agent {
13874
13975class HttpsAgent extends https . Agent {
14076 createConnection ( options , callback ) {
141- if ( isIPAddress ( options . host ) && isPrivateIP ( options . host ) ) {
77+ if ( ipaddr . isValid ( options . host ) && isDisallowedIP ( options . host ) ) {
14278 callback ( new Error ( FORBIDDEN_IP_ADDRESS ) )
14379 return undefined
14480 }
0 commit comments