Errata

Web Application Security

Errata for Web Application Security

Submit your own errata for this product.

The errata list is a list of errors and their corrections that were found after the product was released.

The following errata were submitted by our customers and have not yet been approved or disproved by the author or editor. They solely represent the opinion of the customer.

Color Key: Serious technical mistake Minor technical mistake Language or formatting error Typo Question Note Update

Version Location Description Submitted by Date submitted
Printed Page --
--

For the next printing and edition, we recommend rephrasing the terms "master/slave," "blacklist/whitelist," and "black hat/white hat" to avoid an unintended negative impact on readers who find the terminology offensive.

We are adding alternatives to our word list in June 2020.

Katherine Tozer  Jun 15, 2020 
Chapter 6
First paragraph after Figure 6-2

"Underscore and Lodash expose globals using the underscore symbol $" should read "Underscore and Lodash expose globals using the underscore symbol _"

Martin Leeuwangh  Dec 14, 2020 
Chapter 4
Under heading 'Search Engine Caches', fourth and fifth paras and caption to fig 4-4

'--inurl:<pattern>' should read '-inurl:<pattern>' [i.e., there should be a single, rather than double, '-'].

Martin Leeuwangh  Dec 14, 2020 
Chapter 4
Multiple locations

Several times in chapter 4 the search engine “-“ operator (minus, as in “exclude”) is typed as “--“ as if it was the prefix to a command line argument.

George Brocklehurst  Jul 09, 2021 
Chapter 4
“Accidental Archives” section

The statement “a search for file:// might pull up a previously live download” is entirely false.

The file:// URL scheme references the local filesystem. If you were to click on a file:// link in your browser it would open a local file. This is about as far as it’s possible to get from a live download.

Downloads would use http(s):// or perhaps in some cases ftp://.

George Brocklehurst  Jul 09, 2021 
Chapter 4
“Brute Forcing Subdomains” section

The language in this section is imprecise in ways that are misleading.

Leading up to the example code there are two statements about what is done with the list of possible subdomains: “we fire off a request to <subdomain-guess>.mega-bank.com” and “pinging each time to detect if the subdomain is live”.

The actual implementation does not make any kind of request to the subdomain (including sending a ping). Instead it sends a request to a nameserver to resolve the domain.

George Brocklehurst  Jul 09, 2021 
Other Digital Version Telephone “Phreaking,” Circa 1950
11th paragraph

"knowledge of weaknesses inherit in tone dialing systems"
should read
"knowledge of weaknesses inherent in tone dialing systems"

Dean Ganskop  Jul 08, 2022 
Other Digital Version Chapter 1; Anti-Phreaking Technology, Circa 1960
5th paragraph

"The mechanics of DTMF tones are generated are pretty simple"
should read
"The mechanics of how DTMF tones are generated are pretty simple"

Dean Ganskop  Jul 08, 2022 
Other Digital Version Chapter 2; Introduction to Web Application Reconnaissance
1st paragraph

"patch them before a malicious actor find them"
should read
"patch them before a malicious actor finds them"

Dean Ganskop  Jul 08, 2022 
Other Digital Version Chapter 10. Cross-Site Scripting (XSS); DOM-Based XSS
15th paragraph

"The document.write() call will result in the execution of this hash value.... This will display the current session cookies, ..."

should be

"The document.cookie call will result in the execution of this hash value.... This will display the current session cookies, ..."

Dean Ganskop  Aug 14, 2022 
Other Digital Version Chapter 10. Cross-Site Scripting (XSS); DOM-Based XSS
2nd paragraph

"The major difference between for DOM XSS and other forms of XSS"

should read

"The major difference between DOM XSS and other forms of XSS"

Dean Ganskop  Aug 15, 2022 
1
Figure 3-6

Figure 3-6 is a screenshot of a browser’s JavaScript console session demonstrating the use of localStorage.

localStorage can only store strings, but the example shows an object being stored. The object is converted to the useless string “[Object object]”, which is evident in the following lines showing the contents of localStorage and demonstrating retrieval from localStorage.

George Brocklehurst  Jul 09, 2021 
Other Digital Version 18. Secure Application Architecture, Secure Sockets Layer and Transport Layer Security
4th paragraph

"TSL cannot interpolate with older versions of SSL..."

should be

"TLS cannot interpolate with older versions of SSL..."

Dean Ganskop  Aug 14, 2022 
Other Digital Version 23. Defending Against CSRF Attacks
Anti-CRSF Coding Best Practices heading

"Anti-CRSF Coding Best Practices" heading should be "Anti-CSRF Coding Best Practices"

and

"There are many methods of eliminating or mitigating CRSF risk" should be "There are many methods of eliminating or mitigating CSRF risk"

Dean Ganskop  Aug 31, 2022 
Printed Page 29
N/A

He said that web sockets permit client-client communication. I'm skeptical that web sockets can provide *direct* client-client communication, especially if there is a NAT in the way. I feel like you would normally have two browsers connected to a server, so the server is really in the middle.

JJ Behrens  Sep 24, 2022 
Printed Page 33-34
Bottom of page #33 and top of page #34

In the bottom of page #33 it says: "JavaScript is now used in many applications, from mobile to the internet of things, or IoT."

On page #34 you have nearly the same sentence (just before the Figure 3-2): "JavaScript is now used in many applications, from mobile to IoT."

Also, the word Internet in "internet of things'' should be written with a capital letter. Moreover IoT is the Internet of things so why write it after "or" as it was something different?



Luke Koziarski  Apr 08, 2021 
Printed Page 35
0/10

In the text "lacking an identifier", I think "identifier" is the wrong term. "const" is a keyword. An identifier is a variable name.

Also, on p. 36.7, it says "const...if the value of `age`...changes." The way that comment is written, it sounds like you can change age from 35 to something else. It needs to be clearer that with const variables, only the properties on the variable can change.

JJ Behrens  Sep 24, 2022 
Printed Page 90
6/10

It says "Underscore and Lodash expose globals using the underscore symbol $..." I do believe the symbol is `_`.

JJ Behrens  Sep 24, 2022 
Printed Page 101
The bare minimum of the IM app code

There are 2 mistakes in the way the `send` function gets the data from html resulting `message` variable being always an empty string and `target` variable being always `undefined`. See the code below, I included original code from the book along with fixes.

const send = function() {
const message = document.querySelector('#send').value; // <-- incorrect
const target = document.querySelector('#target').value; // <-- incorrect

const messageFixed = document.querySelector('.input').value; // <-- correct
const targetFixed = document.querySelector('#target').innerText; // <-- correct

https://jsbin.com/ciwotahoni/edit?html,console,output

Luke Koziarski  Apr 11, 2021 
Printed Page 120
1/10

In order to use XHR to exfiltrate data to an attacker's server, the attacker's server needs to serve up the correct CORS headers or the browser won't allow it.

Also, if you use innerHTML with a string containing a script tag, the browser will ignore it, so it's not as easy as the book claims. This StackOverflow post talks more about this: stackoverflow.com/questions/2592092/executing-script-elements-inserted-with-innerhtml

A more typical vector is to use an img tag with a non-existing src and an onerror attribute.

JJ Behrens  Sep 24, 2022 
Printed Page 123
9/10

It says, "A reflected XSS affects the code of the client in the browser directly without relying on a server to relay a message to be rendered with a script to be executed."

This is sometimes true, but not always. For instance, you might have a search field that does a GET to the server, and then the server outputs a search results page containing the unescaped search query. This is still coming from the server. It's just not getting stored in the DB.

See also 125.1.

JJ Behrens  Sep 24, 2022 
Printed Page 126
8/10

It says, "Because DOM XSS never touches a server, it is nearly impossible to detect with static analysis tools or any other type of popular scanner." I'm skeptical of this statement. Static analysis tools don't care if some other part of your codebase is or is not talking to the server. My point is that whether or not your code talks to a server is orthogonal. If the static analysis tool is wary of you using a sink with some dynamic data, it doesn't matter where you got that data.

JJ Behrens  Sep 24, 2022 
Printed Page 128
0/10

Your use of document.write() in this example doesn't make sense because it'd probably write to the wrong place on the page. Hence, this code could work in theory, but I've never seen it work like this in practice. In practice, you'd use someNode.innerHTML.

JJ Behrens  Sep 24, 2022 
Printed Page 134
N/A

The text is skipping over the need for proper CORS headers when using an XHR to talk to a site other than the origin server.

JJ Behrens  Sep 24, 2022 
Printed Page 137
5/10

If you POST a form in order to do a CSRF attack, that doesn't require user interaction. You can use JavaScript to submit the form.

JJ Behrens  Sep 24, 2022 
Printed Page 142
8/10

The text suggests that HTML is a subset of XML. That may have been true for XHTML, but it's certainly not true with HTML5. There are several features in HTML5 that when used cause the content to not be valid XML.

JJ Behrens  Sep 24, 2022 
Printed Page 143
6/10

There is a call to alert() that is missing double quotes around the string.

JJ Behrens  Sep 24, 2022 
Printed Page 147
9/10

It says "An SQL string is escaped in an HTTP payload..." This needs to be reworded because it confusing and misleading. It's not about the fact that it's escaped in an HTTP payload. I mean, the user could have just typed it into a simple form field. Rather, the user used some unexpected characters that break the SQL string that the developer was creating. For instance, the user could use:

' and true; drop tables...; --

JJ Behrens  Sep 24, 2022 
Printed Page 150
8/10

It talks about the 1=1 trick. However, let's suppose the query is:

query = 'select * from users where id = ' + user_id;

That would result in:

query = 'select * from users where id = 1 = 1';

That probably wouldn't work. You probably need something like:

user_id = '0 or 1 = 1';

JJ Behrens  Sep 24, 2022 
Printed Page 150
9/10

There's a query:

select * from users where user = 123abd;

I suspect you need to put that value in quotes.

JJ Behrens  Sep 24, 2022 
Printed Page 151
9/10

There are many places in the book that use the term CLI in ways that I think are not appropriate.

CLI = command line interface

So, MySQL has a CLI where you can run SQL queries in a terminal. However, when a program is talking to MySQL, it's not really using a CLI because there is no command line. In this case, it's better to say SQL interpreter.

Similarly, there are many other places that say CLI when they really mean interpreter or REPL or something like that.

JJ Behrens  Sep 24, 2022 
Printed Page 153
3/10

In the code `const res = await compressImage()`, you're overwriting the res variable that was originally set in `function(req, res)` on p. 152.9. This would prevent the later code, `return res.status(200)` from executing correctly.

JJ Behrens  Sep 24, 2022 
Printed Page 153
153.4

I think you're using the wrong path to the image in the code. The image is actually in the /compressed/ directory.

JJ Behrens  Sep 24, 2022 
Printed Page 154
7/10

It says:

const options = '-c h264 -ab 192k \ convert -dir /videos -s 1x1';

I think that backslash was meant to escape a newline, but it's really just escaping a space which doesn't do what you intended.

JJ Behrens  Sep 24, 2022 
Printed Page 155
9/10

It says, "rather than performing unintended actions against a CLI or interpreter, we are performing unintended actions against an OS."

I'd reword this. You're talking about injecting stuff into bash. bash both has a CLI and is an interpreter. You're not really directly attacking an OS (i.e. by making system calls). You really are just attacking an interpreter, i.e. bash, which happens to itself make system calls into the OS.

JJ Behrens  Sep 24, 2022 
Printed Page 158
6/10

It says:

exec(rm ...

You're missing the quotes.

JJ Behrens  Sep 24, 2022 
Printed Page 195
9/10

"Cannot interplate" should be "cannot interoperate".

JJ Behrens  Sep 24, 2022 
Printed Page 197
9/10

You wrote "264 bits of data". I think you mean "256 bits of data".

By the way, I think your password-handling recommendations are a bit dated. "Cryptographic Right Answers" suggests:

"In order of preference, use scrypt, argon2, bcrypt, and then if nothing else is available PBKDF2."

JJ Behrens  Sep 24, 2022 
Printed Page 201
3/10

You said that "2FA eliminates remote logins to your web applications that were not initiated by the owner of the account." I'd say it helps, but it doesn't fully eliminate this problem. There's still the attack where you convince the user to log into a copycat site. The copycat site can ask for the user's password as well as 2FA and then use those to log into the real site.

JJ Behrens  Sep 24, 2022 
Printed Page 213
8/10

This stuff doesn't make sense:

"Rather than reading the results of a network request, a module sends back its HTML code, including any form data (for example when dealing with authentication). Then the server must be responsible for parsing the HTML code and ensuring no script execution or parameter tampering occurs inside both the HTML code and the authentication logic.

You might consider clarifying in future editions.

I'm also skeptical of your plan in [213.5] where you have different modules within the same app with different OS-level permissions. This might work if you have 5 or fewer modules, but it's not going to work for each of 100 libraries. If you go all the way to microservices, this makes sense. But, your text doesn't match that. You can't have one module log and another module talk to the DB. All the different parts each need to take care of their own logging :-/

JJ Behrens  Sep 24, 2022 
Printed Page 220
4/10

Just because you've switched from GET to POST doesn't mean you've alleviated CSRF.

JJ Behrens  Sep 24, 2022 
Printed Page 236
7/10

This code doesn't make sense. 'hi' is a string. But, running JSON.parse('hi') would raise an exception.

JJ Behrens  Sep 24, 2022 
Printed Page 237
8/10

It says:

Let's assume your sanitizer blocks single and double quotes as well as script tags. You could still run into this issue:

a href...

Notice that in your code, you used double quotes, but you said those were blocked :-/

JJ Behrens  Sep 24, 2022 
Printed Page 238
3/10

It says:

element.innerHTM`L

The backquote is a typo.

JJ Behrens  Sep 24, 2022 
Printed Page 239
9/10

The text suggests that merely embedding a script tag in a URL will cause the script tag to execute when you load the URL. I didn't think that would work, and in fact, in my testing, it doesn't.

JJ Behrens  Sep 24, 2022 
Printed Page 248
6/10

It says:

if (!origin || referrer) { return false; }

It should probably say:

if (!(origin || referrer)) { return false; }

JJ Behrens  Sep 24, 2022 
Printed Page 252
6/10

You wrote:

isValid = validLocations.includes(referer)...

The referer might contain a path as well, and that would break the code.

Also, consider the else branch. You might not even get a referer with a GET if the user just types in the URL manually.

JJ Behrens  Sep 24, 2022 
Printed Page 253
8/10

You wrote:

your users will be able to feel more comfortable entering your web application from other origins

This doesn't make sense. They don't know enough to feel uncomfortable, and with CSRF, it's not like they're *choosing* to interact with a domain from another domain.

JJ Behrens  Sep 24, 2022 
Printed Page 256
7/10

It says that schema validation is not supported with JSON. However, there are tools and libraries to validate JSON. See JSON Schema.

JJ Behrens  Sep 24, 2022 
Printed Page 257
2/10

It says:

JSON, a format that simply stores key/value pairs in a string-based format.

I think this is not correct. For instance the following is valid JSON, but it's not a key/value pair:

5

JJ Behrens  Sep 24, 2022 
Printed Page 262
N/A

I'm skeptical of this approach to handling SQL injection. However, it's not spelled out in enough detail for me to fully know for sure. Also, the select quote thing on p. 263 doesn't make sense.

Usually, your library for interacting with the DB understands something like the following:

db.query('select * from users where id = ?', user_id)

Under the covers, the library could be using prepared statements, or it could be escaping the user_id and using string interpolation. In any case, that's what the calling code usually looks like.

The code on p. 262.4 looks especially suspicious because how do you inject that value 12 when setting @price? If you use string concatenation, it'd still be susceptible to SQL injection.

JJ Behrens  Sep 24, 2022 
Printed Page 277
1/10

There's a blob of text at the top of the page that has a bunch of arrows. I think it was supposed to be a table. However, since it lost its formatting, it no longer makes sense.

JJ Behrens  Sep 24, 2022 
Printed Page 278
1/10

It talks about running third-party integrations on separate servers.

I have concerns about this section:

It doesn't do enough to differentiate server software (like MySQL) vs. small little libraries (like a JavaScript or Python library to parse XML or do structured logging). Sure, you can run MySQL on a separate server, but if it's holding your most important data, it already has access to...all of your most important data.

If there were some other server software that were compromised, it'd still be in the same VPC and could reach out to attack other things.

If it's just a library, it's not realistic to push it out of process. A typical JavaScript or Python application might have a 100 dependencies. Trying to get all of them to work in separate processes would be prohibitive.

Realistically, you can have separate microservices, and that segregation is useful. However, even each of those separate microservices might have 10s or 100s of dependencies running in process.

If you really can't trust a piece of code, I suggest you get it out of your VM and/or VPC entirely.

JJ Behrens  Sep 24, 2022 
Printed Page 284
0/10

It talks about sockets when it should really talk about WebSockets.

JJ Behrens  Sep 24, 2022 
Printed Page 287
5/10

The text implies that PDF is an XML format. Although PDFs can be converted to XML, PDFs themselves are not XML.

JJ Behrens  Sep 24, 2022 
Printed Page 287
8/10

It talks about protecting against injection attacks against CLIs.

It suggests the principle of least authority and separation of concerns. I think these are secondary approaches. The primary approaches are:

When executing a subprocess, use a function that lets you skip the shell and specify all of the arguments in an array. For instance, in Python, there's:

subprocess.run(["ls", "-l"])

If you absolutely must use a shell, then you can escape any special characters to protect against injection attacks. In Python, there's:

shlex.quote(s)

I'm sure there are similar things in the JavaScript world.

JJ Behrens  Sep 24, 2022 
Printed Page 287
9/10

The text mentions "backtracing". I think you mean "backtracking".

JJ Behrens  Sep 24, 2022