Guy Podjarny
09/01/07, 16:32
Another similar option is to use a single-use random value (not
encrypted), that gets invalidated after it's served back.=20
You can save the random value on the (non persistent) session
(server-side), and serve the PDF only if the correct random value is
provided.=20
Once a random value has been used, it's cleared (single-use).
In any case where the wrong value is provided - recreate a random value,
save it on the session, and redirect to the PDF with it (same behavior
as when the token isn't provided at all).
So the flow is:
IF the URL Session[X] !=3D null (we have a previously created random =
val)
AND request contains token_query AND token_query=3D=3DSession[X]:
Session[X] =3D null -- > Clear the token (it's only
good for one use)
serve the PDF resource as an in-line resource
ELSE:
calculate X =3D new random token value
Session["token"] =3D X -- > save X on session (works for that
user only)
redirect to file.pdf?token_query=3DX
=20
Time delays can be added for extra security, but since the session isn't
persistent, it'll usually not be required.
One more note about the redirect:
It seems that firefox retains the fragment portion when you redirect.=20
So if you're browsing:
http://server/page.aspx#target And you redirect to
http://server/page.aspx, Firefox will keep the #target fragment!
To work around this, you can redirect to http://server/page.aspx#a - by
adding a fragment to your redirect, you make firefox get rid of the old
one.=20
Cheers,
Guypo=20
-----Original Message-----
From: Amit Klein [mailto:aksecurity@gmail.com]=20
Sent: Thursday, January 04, 2007 4:38 PM
To: bugtraq@securityfocus.com; Web Security
Subject: Re: [WEB SECURITY] Universal XSS with PDF files: highly
dangerous
Updates:
1. In private communication, Tom Spector observed that the cookie
doesn't add any significant security. In retrospect, I could have
omitted it completely. It's there as a remnant of a previous idea I had.
In other words, I see nothing wrong with the following, simpler and more
elegant algorithm ("Look ma - no cookie"):
IF the URL doesn't contain token_query, then:
calculate X=3Dencrypt_with_key(server_time, client_IP_address)
redirect to file.pdf?token_query=3DX
=20
ELSE IF the URL contains token_query, and
decrypt(token_query).IP_address=3D=3Dclient_IP_add ress and
decrypt(token_query).time>server_time-10sec
serve the PDF resource as an in-line resource
=20
ELSE
serve the PDF resource as a "save to disk" resource via a proper
choice of the Content-Type header (and/or an attachment, via
Content-Disposition).
And big thanks to Tom who pointed this out.
2. While thinking more about this solution, I observed that if the
attacker can have an "agent" sharing the same IP address with the victim
(by agent I mean an entity that can communicate with the target web site
and read back its response data), then the algorithms I suggested will
not be effective. Note that an attacker can share IP address with the
victim when both share a forward proxy (e.g. some universities and
ISPs), or when the attacker and victim share the same machine
(multi-user environment). Still, that narrows down the attack surface
significantly.
Thanks,
-Amit
Amit Klein wrote:
> It seems that I forgot all about Flash when I wrote that (the=20
> irony...). The solution I proposed is not secure enough as-is. It is=20
> trivial to write a SWF object that will request=20
> file.pdf?token_query=3D123 and add a "Cookie: token_cookie=3D123". =
This is
> discussed in yours truly's "Forging HTTP request headers with Flash" (
> http://www.securityfocus.com/archive/1/441014) and in Rapid7's "Rapid7
> Advisory R7-0026 - HTTP Header Injection Vulnerabilities in the Flash=20
> Player Plugin" ( http://www.rapid7.com/advisories/R7-0026.jsp).
> Even adding cryptographic secret, time-based entropy or use counter=20
> doesn't help - all this can be circumvented by a server script on the=20
> attacker's site preparing the HTTP request and communicating it in=20
> real-time to the SWF object at the victim's browser.
> =20
> The solution I could come up with is to tie X to the IP address of the
> client. Yes, I know - it's ugly, and it doesn't work 100% of the=20
> cases. But you stand nothing to lose if you simply fall back to the=20
> "save to disk" option, suggested by an anonymous SlashDot submitter (=20
>
http://it.slashdot.org/comments.pl?sid=3D214868&threshold=3D1&commentsort=
=3D0&
mode=3Dthread&cid=3D17450834=20
>
<http://it.slashdot.org/comments.pl?sid=3D214868&threshold=3D1&commentsor=
t=3D0
&mode=3Dthread&cid=3D17450834>).
> =20
> So the more secure solution, as I see it, is as following:
> =20
> Apply only for PDF resources:
> =20
> IF the URL doesn't contain token_query, then:
> calculate X=3Dencrypt_with_key(server_time, client_IP_address)
> redirect to file.pdf?token_query=3DX with Set-Cookie: =
token_cookie=3DX=20
> to expire at server_time+10sec.
> =20
> ELSE IF the URL contains token_query, and =
token_query=3D=3Dtoken_cookie=20
> and decrypt(token_query).IP_address=3D=3Dclient_IP_add ress and=20
> decrypt(token_query).time>server_time-10sec
> serve the PDF resource as an in-line resource
> =20
> ELSE
> serve the PDF resource as a "save to disk" resource via a proper=20
> choice of the Content-Type header (and/or an attachment, via=20
> Content-Disposition).
> =20
> Hopefully this should work. But it's definitely less elegant than the=20
> original (flawed) suggestion.
> =20
> -Amit
> =20
------------------------------------------------------------------------
----
The Web Security Mailing List:=20
http://www.webappsec.org/lists/websecurity/
The Web Security Mailing List Archives:=20
http://www.webappsec.org/lists/websecurity/archive/
http://www.webappsec.org/rss/websecurity.rss [RSS Feed]
encrypted), that gets invalidated after it's served back.=20
You can save the random value on the (non persistent) session
(server-side), and serve the PDF only if the correct random value is
provided.=20
Once a random value has been used, it's cleared (single-use).
In any case where the wrong value is provided - recreate a random value,
save it on the session, and redirect to the PDF with it (same behavior
as when the token isn't provided at all).
So the flow is:
IF the URL Session[X] !=3D null (we have a previously created random =
val)
AND request contains token_query AND token_query=3D=3DSession[X]:
Session[X] =3D null -- > Clear the token (it's only
good for one use)
serve the PDF resource as an in-line resource
ELSE:
calculate X =3D new random token value
Session["token"] =3D X -- > save X on session (works for that
user only)
redirect to file.pdf?token_query=3DX
=20
Time delays can be added for extra security, but since the session isn't
persistent, it'll usually not be required.
One more note about the redirect:
It seems that firefox retains the fragment portion when you redirect.=20
So if you're browsing:
http://server/page.aspx#target And you redirect to
http://server/page.aspx, Firefox will keep the #target fragment!
To work around this, you can redirect to http://server/page.aspx#a - by
adding a fragment to your redirect, you make firefox get rid of the old
one.=20
Cheers,
Guypo=20
-----Original Message-----
From: Amit Klein [mailto:aksecurity@gmail.com]=20
Sent: Thursday, January 04, 2007 4:38 PM
To: bugtraq@securityfocus.com; Web Security
Subject: Re: [WEB SECURITY] Universal XSS with PDF files: highly
dangerous
Updates:
1. In private communication, Tom Spector observed that the cookie
doesn't add any significant security. In retrospect, I could have
omitted it completely. It's there as a remnant of a previous idea I had.
In other words, I see nothing wrong with the following, simpler and more
elegant algorithm ("Look ma - no cookie"):
IF the URL doesn't contain token_query, then:
calculate X=3Dencrypt_with_key(server_time, client_IP_address)
redirect to file.pdf?token_query=3DX
=20
ELSE IF the URL contains token_query, and
decrypt(token_query).IP_address=3D=3Dclient_IP_add ress and
decrypt(token_query).time>server_time-10sec
serve the PDF resource as an in-line resource
=20
ELSE
serve the PDF resource as a "save to disk" resource via a proper
choice of the Content-Type header (and/or an attachment, via
Content-Disposition).
And big thanks to Tom who pointed this out.
2. While thinking more about this solution, I observed that if the
attacker can have an "agent" sharing the same IP address with the victim
(by agent I mean an entity that can communicate with the target web site
and read back its response data), then the algorithms I suggested will
not be effective. Note that an attacker can share IP address with the
victim when both share a forward proxy (e.g. some universities and
ISPs), or when the attacker and victim share the same machine
(multi-user environment). Still, that narrows down the attack surface
significantly.
Thanks,
-Amit
Amit Klein wrote:
> It seems that I forgot all about Flash when I wrote that (the=20
> irony...). The solution I proposed is not secure enough as-is. It is=20
> trivial to write a SWF object that will request=20
> file.pdf?token_query=3D123 and add a "Cookie: token_cookie=3D123". =
This is
> discussed in yours truly's "Forging HTTP request headers with Flash" (
> http://www.securityfocus.com/archive/1/441014) and in Rapid7's "Rapid7
> Advisory R7-0026 - HTTP Header Injection Vulnerabilities in the Flash=20
> Player Plugin" ( http://www.rapid7.com/advisories/R7-0026.jsp).
> Even adding cryptographic secret, time-based entropy or use counter=20
> doesn't help - all this can be circumvented by a server script on the=20
> attacker's site preparing the HTTP request and communicating it in=20
> real-time to the SWF object at the victim's browser.
> =20
> The solution I could come up with is to tie X to the IP address of the
> client. Yes, I know - it's ugly, and it doesn't work 100% of the=20
> cases. But you stand nothing to lose if you simply fall back to the=20
> "save to disk" option, suggested by an anonymous SlashDot submitter (=20
>
http://it.slashdot.org/comments.pl?sid=3D214868&threshold=3D1&commentsort=
=3D0&
mode=3Dthread&cid=3D17450834=20
>
<http://it.slashdot.org/comments.pl?sid=3D214868&threshold=3D1&commentsor=
t=3D0
&mode=3Dthread&cid=3D17450834>).
> =20
> So the more secure solution, as I see it, is as following:
> =20
> Apply only for PDF resources:
> =20
> IF the URL doesn't contain token_query, then:
> calculate X=3Dencrypt_with_key(server_time, client_IP_address)
> redirect to file.pdf?token_query=3DX with Set-Cookie: =
token_cookie=3DX=20
> to expire at server_time+10sec.
> =20
> ELSE IF the URL contains token_query, and =
token_query=3D=3Dtoken_cookie=20
> and decrypt(token_query).IP_address=3D=3Dclient_IP_add ress and=20
> decrypt(token_query).time>server_time-10sec
> serve the PDF resource as an in-line resource
> =20
> ELSE
> serve the PDF resource as a "save to disk" resource via a proper=20
> choice of the Content-Type header (and/or an attachment, via=20
> Content-Disposition).
> =20
> Hopefully this should work. But it's definitely less elegant than the=20
> original (flawed) suggestion.
> =20
> -Amit
> =20
------------------------------------------------------------------------
----
The Web Security Mailing List:=20
http://www.webappsec.org/lists/websecurity/
The Web Security Mailing List Archives:=20
http://www.webappsec.org/lists/websecurity/archive/
http://www.webappsec.org/rss/websecurity.rss [RSS Feed]