[xwiki-devs] [proposal] Add support for secet token verification
Hi, I would like to add support for secret token verification to prevent CSRF attacks (see http://jira.xwiki.org/jira/browse/XWIKI-4873). The main idea is to add a random token as a parameter to each request that requires edit/comment/admin rights and check that this token is present on the server side. Since there are many ways one can modify documents, it would require many changes all over the place, in particular: * add a public method to XWikiContext: String getSecretToken() that generates a random token and caches it in the session * add a public method to XWikiRightService*: boolean isRequestLegitimate(String action, XWikiContext context) to check if the given action is allowed to be executed * add the following API methods to Context: String getSecretToken() boolean checkSecretToken() for including the secret token into forms/AJAX requests and checking that the current request is legitimate * add a new configuration parameter core.useSecretTokenValidation for disabling this functionality, and the corresponding method useSecretTokenValidation() to CoreConfiguration and DefaultCoreConfiguration * use the secret token (hidden input for forms or parameter of GET requests) in all templates (*.vm files in web/standard and skins, velocity macros in applications/**/resources/*.xml) * check the secret token in Save/Delete/Upload/etc.-Actions and throw an exception to deny the access if the check fails * check the secret token in all templates that directly modify data (e.g. web/standard/src/main/webapp/templates/admin.vm) * fix all selenium tests that directly modify pages using the open(...) method * make sure nothing else is broken WDYT? Thanks, Alex
Instead of having all these secret tokens and modifying all over the place, what about using something like realm-based-authentication (implemented in cookies); the presence of one of these crypto-cookies performs the same role as your nonce-token parameter. However, by having the verificartion of these cookies integrated in with the overall login/access control mechanism of Xwiki, you can achieve the same thing, without as many modifications and incompatibilities (IMHO). The use of realms allows for different levels of security and access for different components... e.g. one might have public, private, and admin realms and different cookies would be generated containing this realm information (ie. what spaces can be accessed from any requests associated w/ that cookie). The cookies are signed and timestamped and therefore tamper-proof... You can generate these cookie-tokens as often as you like, and they contain a signed timestamp that can allow you to set quick expiry - on the order of one minute, or a few tens of seconds... See http://www.frogdot.org/mod_auth_mda/mechanicg.html http://www.frogdot.org/mod_auth_mda/mechanics.html http://www.frogdot.org/mod_auth_mda/download.html Niels http://nielsmayer.com On Sun, Mar 7, 2010 at 11:46 AM, Alex Busenius <the_unknown@gmx.net> wrote:
Hi,
I would like to add support for secret token verification to prevent CSRF attacks (see http://jira.xwiki.org/jira/browse/XWIKI-4873).
The main idea is to add a random token as a parameter to each request that requires edit/comment/admin rights and check that this token is present on the server side. Since there are many ways one can modify documents, it would require many changes all over the place, in particular:
* add a public method to XWikiContext: String getSecretToken() that generates a random token and caches it in the session * add a public method to XWikiRightService*: boolean isRequestLegitimate(String action, XWikiContext context) to check if the given action is allowed to be executed * add the following API methods to Context: String getSecretToken() boolean checkSecretToken() for including the secret token into forms/AJAX requests and checking that the current request is legitimate * add a new configuration parameter core.useSecretTokenValidation for disabling this functionality, and the corresponding method useSecretTokenValidation() to CoreConfiguration and DefaultCoreConfiguration * use the secret token (hidden input for forms or parameter of GET requests) in all templates (*.vm files in web/standard and skins, velocity macros in applications/**/resources/*.xml) * check the secret token in Save/Delete/Upload/etc.-Actions and throw an exception to deny the access if the check fails * check the secret token in all templates that directly modify data (e.g. web/standard/src/main/webapp/templates/admin.vm) * fix all selenium tests that directly modify pages using the open(...) method * make sure nothing else is broken
WDYT?
Thanks, Alex _______________________________________________ devs mailing list devs@xwiki.org http://lists.xwiki.org/mailman/listinfo/devs
Hi, I don't see how realm-based-authentication can prevent CSRF attacks. It doesn't matter how the authentication token is generated, as long as it is stored in the cookies, the browser will send it automatically also for malicious requests. It could only work if you set a very short expiration time and make users authenticate themselves each time they want to edit a page, which is quite inconvenient for a Wiki. So, just in case it wasn't clear, the secret token is *not* stored in the cookies. It is stored on the server side in the session object and is included into the HTML. Alex On 03/08/2010 11:00 PM, Niels Mayer wrote:
Instead of having all these secret tokens and modifying all over the place, what about using something like realm-based-authentication (implemented in cookies); the presence of one of these crypto-cookies performs the same role as your nonce-token parameter. However, by having the verificartion of these cookies integrated in with the overall login/access control mechanism of Xwiki, you can achieve the same thing, without as many modifications and incompatibilities (IMHO).
The use of realms allows for different levels of security and access for different components... e.g. one might have public, private, and admin realms and different cookies would be generated containing this realm information (ie. what spaces can be accessed from any requests associated w/ that cookie). The cookies are signed and timestamped and therefore tamper-proof... You can generate these cookie-tokens as often as you like, and they contain a signed timestamp that can allow you to set quick expiry - on the order of one minute, or a few tens of seconds...
See http://www.frogdot.org/mod_auth_mda/mechanicg.html http://www.frogdot.org/mod_auth_mda/mechanics.html http://www.frogdot.org/mod_auth_mda/download.html
Niels http://nielsmayer.com
On Sun, Mar 7, 2010 at 11:46 AM, Alex Busenius <the_unknown@gmx.net <mailto:the_unknown@gmx.net>> wrote:
Hi,
I would like to add support for secret token verification to prevent CSRF attacks (see http://jira.xwiki.org/jira/browse/XWIKI-4873).
The main idea is to add a random token as a parameter to each request that requires edit/comment/admin rights and check that this token is present on the server side. Since there are many ways one can modify documents, it would require many changes all over the place, in particular:
On 03/08/2010 11:00 PM, Niels Mayer wrote:
Instead of having all these secret tokens and modifying all over the place, what about using something like realm-based-authentication (implemented in cookies); the presence of one of these crypto-cookies performs the same role as your nonce-token parameter. However, by having the verificartion of these cookies integrated in with the overall login/access control mechanism of Xwiki, you can achieve the same thing, without as many modifications and incompatibilities (IMHO).
First, as Alex said, cookies are not an option since CrossSite requests are valid, normal requests, and they will use the correct cookies. Second, I already analyzed the possibility of using digest authentication instead of basic (for WebDAV for example), and that's not possible with XWiki, since it requires access to the plain text password. With the current way that passwords are stored (as any object property), it would be too unsafe to do that.
The use of realms allows for different levels of security and access for different components... e.g. one might have public, private, and admin realms and different cookies would be generated containing this realm information (ie. what spaces can be accessed from any requests associated w/ that cookie). The cookies are signed and timestamped and therefore tamper-proof... You can generate these cookie-tokens as often as you like, and they contain a signed timestamp that can allow you to set quick expiry - on the order of one minute, or a few tens of seconds...
See http://www.frogdot.org/mod_auth_mda/mechanicg.html http://www.frogdot.org/mod_auth_mda/mechanics.html http://www.frogdot.org/mod_auth_mda/download.html
Niels http://nielsmayer.com
On Sun, Mar 7, 2010 at 11:46 AM, Alex Busenius<the_unknown@gmx.net> wrote:
Hi,
I would like to add support for secret token verification to prevent CSRF attacks (see http://jira.xwiki.org/jira/browse/XWIKI-4873).
The main idea is to add a random token as a parameter to each request that requires edit/comment/admin rights and check that this token is present on the server side. Since there are many ways one can modify documents, it would require many changes all over the place, in particular:
* add a public method to XWikiContext: String getSecretToken() that generates a random token and caches it in the session * add a public method to XWikiRightService*: boolean isRequestLegitimate(String action, XWikiContext context) to check if the given action is allowed to be executed * add the following API methods to Context: String getSecretToken() boolean checkSecretToken() for including the secret token into forms/AJAX requests and checking that the current request is legitimate * add a new configuration parameter core.useSecretTokenValidation for disabling this functionality, and the corresponding method useSecretTokenValidation() to CoreConfiguration and DefaultCoreConfiguration * use the secret token (hidden input for forms or parameter of GET requests) in all templates (*.vm files in web/standard and skins, velocity macros in applications/**/resources/*.xml) * check the secret token in Save/Delete/Upload/etc.-Actions and throw an exception to deny the access if the check fails * check the secret token in all templates that directly modify data (e.g. web/standard/src/main/webapp/templates/admin.vm) * fix all selenium tests that directly modify pages using the open(...) method * make sure nothing else is broken
WDYT?
-- Sergiu Dumitriu http://purl.org/net/sergiu/
I had thought about proposing this myself but decided against it because it seems to me like a workaround for problems which can be solved in other ways. Suppose we were to add a check to the actions which alter data which made sure the request method was 'post' and made it configurable in one of the configuration files? We would have to look over the default skins for incorrect links and leave the configuration option off by default for backward compatibility at least until the next major version but we could provide wiki operators the ability to prevent CSRF. Caleb Sergiu Dumitriu wrote:
On 03/08/2010 11:00 PM, Niels Mayer wrote:
Instead of having all these secret tokens and modifying all over the place, what about using something like realm-based-authentication (implemented in cookies); the presence of one of these crypto-cookies performs the same role as your nonce-token parameter. However, by having the verificartion of these cookies integrated in with the overall login/access control mechanism of Xwiki, you can achieve the same thing, without as many modifications and incompatibilities (IMHO).
First, as Alex said, cookies are not an option since CrossSite requests are valid, normal requests, and they will use the correct cookies.
Second, I already analyzed the possibility of using digest authentication instead of basic (for WebDAV for example), and that's not possible with XWiki, since it requires access to the plain text password. With the current way that passwords are stored (as any object property), it would be too unsafe to do that.
The use of realms allows for different levels of security and access for different components... e.g. one might have public, private, and admin realms and different cookies would be generated containing this realm information (ie. what spaces can be accessed from any requests associated w/ that cookie). The cookies are signed and timestamped and therefore tamper-proof... You can generate these cookie-tokens as often as you like, and they contain a signed timestamp that can allow you to set quick expiry - on the order of one minute, or a few tens of seconds...
See http://www.frogdot.org/mod_auth_mda/mechanicg.html http://www.frogdot.org/mod_auth_mda/mechanics.html http://www.frogdot.org/mod_auth_mda/download.html
Niels http://nielsmayer.com
On Sun, Mar 7, 2010 at 11:46 AM, Alex Busenius<the_unknown@gmx.net> wrote:
Hi,
I would like to add support for secret token verification to prevent CSRF attacks (see http://jira.xwiki.org/jira/browse/XWIKI-4873).
The main idea is to add a random token as a parameter to each request that requires edit/comment/admin rights and check that this token is present on the server side. Since there are many ways one can modify documents, it would require many changes all over the place, in particular:
* add a public method to XWikiContext: String getSecretToken() that generates a random token and caches it in the session * add a public method to XWikiRightService*: boolean isRequestLegitimate(String action, XWikiContext context) to check if the given action is allowed to be executed * add the following API methods to Context: String getSecretToken() boolean checkSecretToken() for including the secret token into forms/AJAX requests and checking that the current request is legitimate * add a new configuration parameter core.useSecretTokenValidation for disabling this functionality, and the corresponding method useSecretTokenValidation() to CoreConfiguration and DefaultCoreConfiguration * use the secret token (hidden input for forms or parameter of GET requests) in all templates (*.vm files in web/standard and skins, velocity macros in applications/**/resources/*.xml) * check the secret token in Save/Delete/Upload/etc.-Actions and throw an exception to deny the access if the check fails * check the secret token in all templates that directly modify data (e.g. web/standard/src/main/webapp/templates/admin.vm) * fix all selenium tests that directly modify pages using the open(...) method * make sure nothing else is broken
WDYT?
Unfortunately, using POST requests instead of GET requests is not enough. It will not prevent attacks that use forms and/or JavaScript to generate POST requests. Alex On 03/09/2010 02:48 PM, Caleb James DeLisle wrote:
I had thought about proposing this myself but decided against it because it seems to me like a workaround for problems which can be solved in other ways.
Suppose we were to add a check to the actions which alter data which made sure the request method was 'post' and made it configurable in one of the configuration files? We would have to look over the default skins for incorrect links and leave the configuration option off by default for backward compatibility at least until the next major version but we could provide wiki operators the ability to prevent CSRF.
Caleb
Take a look at the "sammy is my hero" worm, myspace sent a hash to the user like the one you propose, the worm made the required get request to get the hash, then made the post along with the hash. What prevents javascript from opening the page with the hash in an iframe and then reading in the iframe to get the hash, then creating a form with the required data and posting it to the save action? If we were to combine a requirement for post requests with checking of the referrer header, then we would block links, forms and javascript based attacks leaving only an attack through older versions of flash which support referrer forgery and at this point the difficulty of the attack becomes such that we need to consider a wider array of attack vectors. Caleb Alex Busenius wrote:
Unfortunately, using POST requests instead of GET requests is not enough. It will not prevent attacks that use forms and/or JavaScript to generate POST requests.
Alex
On 03/09/2010 02:48 PM, Caleb James DeLisle wrote:
I had thought about proposing this myself but decided against it because it seems to me like a workaround for problems which can be solved in other ways.
Suppose we were to add a check to the actions which alter data which made sure the request method was 'post' and made it configurable in one of the configuration files? We would have to look over the default skins for incorrect links and leave the configuration option off by default for backward compatibility at least until the next major version but we could provide wiki operators the ability to prevent CSRF.
Caleb
_______________________________________________ devs mailing list devs@xwiki.org http://lists.xwiki.org/mailman/listinfo/devs
On 03/10/2010 07:44 PM, Caleb James DeLisle wrote:
Take a look at the "sammy is my hero" worm, myspace sent a hash to the user like the one you propose, the worm made the required get request to get the hash, then made the post along with the hash. What prevents javascript from opening the page with the hash in an iframe and then reading in the iframe to get the hash, then creating a form with the required data and posting it to the save action?
If we were to combine a requirement for post requests with checking of the referrer header, then we would block links, forms and javascript based attacks leaving only an attack through older versions of flash which support referrer forgery and at this point the difficulty of the attack becomes such that we need to consider a wider array of attack vectors.
Sammy also required that XSS is enabled. Protecting from attacks originating in the wiki is kind of impossible at the moment, since JS can be inserted anywhere, and there's no (nice) way to prevent attacks from JS inside the application. As long as JS can be inserted, an attacker can do all the steps that the client would do to perform an action. The secret token works as a prevention mechanism when the attack comes from another site because the browser security model prevents the attack code to read the form.
Caleb
Alex Busenius wrote:
Unfortunately, using POST requests instead of GET requests is not enough. It will not prevent attacks that use forms and/or JavaScript to generate POST requests.
Alex
On 03/09/2010 02:48 PM, Caleb James DeLisle wrote:
I had thought about proposing this myself but decided against it because it seems to me like a workaround for problems which can be solved in other ways.
Suppose we were to add a check to the actions which alter data which made sure the request method was 'post' and made it configurable in one of the configuration files? We would have to look over the default skins for incorrect links and leave the configuration option off by default for backward compatibility at least until the next major version but we could provide wiki operators the ability to prevent CSRF.
Caleb
_______________________________________________ devs mailing list devs@xwiki.org http://lists.xwiki.org/mailman/listinfo/devs
_______________________________________________ devs mailing list devs@xwiki.org http://lists.xwiki.org/mailman/listinfo/devs
-- Sergiu Dumitriu http://purl.org/net/sergiu/
Sergiu Dumitriu wrote:
On 03/10/2010 07:44 PM, Caleb James DeLisle wrote:
Take a look at the "sammy is my hero" worm, myspace sent a hash to the user like the one you propose, the worm made the required get request to get the hash, then made the post along with the hash. What prevents javascript from opening the page with the hash in an iframe and then reading in the iframe to get the hash, then creating a form with the required data and posting it to the save action?
If we were to combine a requirement for post requests with checking of the referrer header, then we would block links, forms and javascript based attacks leaving only an attack through older versions of flash which support referrer forgery and at this point the difficulty of the attack becomes such that we need to consider a wider array of attack vectors.
Sammy also required that XSS is enabled.
Protecting from attacks originating in the wiki is kind of impossible at the moment, since JS can be inserted anywhere, and there's no (nice) way to prevent attacks from JS inside the application. As long as JS can be inserted, an attacker can do all the steps that the client would do to perform an action.
The secret token works as a prevention mechanism when the attack comes from another site because the browser security model prevents the attack code to read the form.
I just did a few tests on iframes and I was wrong, they do have good same origin policy. Caleb
Caleb
Alex Busenius wrote:
Unfortunately, using POST requests instead of GET requests is not enough. It will not prevent attacks that use forms and/or JavaScript to generate POST requests.
Alex
On 03/09/2010 02:48 PM, Caleb James DeLisle wrote:
I had thought about proposing this myself but decided against it because it seems to me like a workaround for problems which can be solved in other ways.
Suppose we were to add a check to the actions which alter data which made sure the request method was 'post' and made it configurable in one of the configuration files? We would have to look over the default skins for incorrect links and leave the configuration option off by default for backward compatibility at least until the next major version but we could provide wiki operators the ability to prevent CSRF.
Caleb
_______________________________________________ devs mailing list devs@xwiki.org http://lists.xwiki.org/mailman/listinfo/devs
_______________________________________________ devs mailing list devs@xwiki.org http://lists.xwiki.org/mailman/listinfo/devs
I don't want this proposal to die because of unnecessary noise which I introduced, I have thought about it and I am in agreement with the general idea of sending the user a hash which must be returned with the post in order for the data to be saved. I don't like adding code to xwiki-core so I suggest this be made into a component. We would need 2 functions: String getToken() boolean isTokenValid(String token) getToken uses org.xwiki.bridge.DocumentAccessBridge.getCurrentUser() to get the user who called it and the user name is stored in a HashMap of <String, String> with a random string of text. If getToken finds a token already in the map, it returns that token (so it may be called multiple times in the generation of a page) isTokenValid checks the current user against the token then removes the entry from the HashMap so the token may not be reused. If a configuration parameter is specified to disable the component, getToken returns "" and isTokenValid returns true. WDYT? Caleb Caleb James DeLisle wrote:
Sergiu Dumitriu wrote:
On 03/10/2010 07:44 PM, Caleb James DeLisle wrote:
Take a look at the "sammy is my hero" worm, myspace sent a hash to the user like the one you propose, the worm made the required get request to get the hash, then made the post along with the hash. What prevents javascript from opening the page with the hash in an iframe and then reading in the iframe to get the hash, then creating a form with the required data and posting it to the save action?
If we were to combine a requirement for post requests with checking of the referrer header, then we would block links, forms and javascript based attacks leaving only an attack through older versions of flash which support referrer forgery and at this point the difficulty of the attack becomes such that we need to consider a wider array of attack vectors. Sammy also required that XSS is enabled.
Protecting from attacks originating in the wiki is kind of impossible at the moment, since JS can be inserted anywhere, and there's no (nice) way to prevent attacks from JS inside the application. As long as JS can be inserted, an attacker can do all the steps that the client would do to perform an action.
The secret token works as a prevention mechanism when the attack comes from another site because the browser security model prevents the attack code to read the form.
I just did a few tests on iframes and I was wrong, they do have good same origin policy.
Caleb
Caleb
Alex Busenius wrote:
Unfortunately, using POST requests instead of GET requests is not enough. It will not prevent attacks that use forms and/or JavaScript to generate POST requests.
Alex
On 03/09/2010 02:48 PM, Caleb James DeLisle wrote:
I had thought about proposing this myself but decided against it because it seems to me like a workaround for problems which can be solved in other ways.
Suppose we were to add a check to the actions which alter data which made sure the request method was 'post' and made it configurable in one of the configuration files? We would have to look over the default skins for incorrect links and leave the configuration option off by default for backward compatibility at least until the next major version but we could provide wiki operators the ability to prevent CSRF.
Caleb
_______________________________________________ devs mailing list devs@xwiki.org http://lists.xwiki.org/mailman/listinfo/devs
_______________________________________________ devs mailing list devs@xwiki.org http://lists.xwiki.org/mailman/listinfo/devs
_______________________________________________ devs mailing list devs@xwiki.org http://lists.xwiki.org/mailman/listinfo/devs
Hi Caleb, Caleb James DeLisle wrote:
I don't want this proposal to die because of unnecessary noise which I introduced, I have thought about it and I am in agreement with the general idea of sending the user a hash which must be returned with the post in order for the data to be saved.
I don't like adding code to xwiki-core so I suggest this be made into a component. We would need 2 functions: String getToken() boolean isTokenValid(String token)
getToken uses org.xwiki.bridge.DocumentAccessBridge.getCurrentUser() to get the user who called it and the user name is stored in a HashMap of <String, String> with a random string of text.
If getToken finds a token already in the map, it returns that token (so it may be called multiple times in the generation of a page)
So the token is the same for consecutive (GET) requests coming from the same user?
isTokenValid checks the current user against the token then removes the entry from the HashMap so the token may not be reused.
What happens if the user opens in edit mode two different pages? Isn't the second save invalidated by the first save? Thanks, Marius
If a configuration parameter is specified to disable the component, getToken returns "" and isTokenValid returns true.
WDYT?
Caleb
Caleb James DeLisle wrote:
Sergiu Dumitriu wrote:
On 03/10/2010 07:44 PM, Caleb James DeLisle wrote:
Take a look at the "sammy is my hero" worm, myspace sent a hash to the user like the one you propose, the worm made the required get request to get the hash, then made the post along with the hash. What prevents javascript from opening the page with the hash in an iframe and then reading in the iframe to get the hash, then creating a form with the required data and posting it to the save action?
If we were to combine a requirement for post requests with checking of the referrer header, then we would block links, forms and javascript based attacks leaving only an attack through older versions of flash which support referrer forgery and at this point the difficulty of the attack becomes such that we need to consider a wider array of attack vectors. Sammy also required that XSS is enabled.
Protecting from attacks originating in the wiki is kind of impossible at the moment, since JS can be inserted anywhere, and there's no (nice) way to prevent attacks from JS inside the application. As long as JS can be inserted, an attacker can do all the steps that the client would do to perform an action.
The secret token works as a prevention mechanism when the attack comes from another site because the browser security model prevents the attack code to read the form. I just did a few tests on iframes and I was wrong, they do have good same origin policy.
Caleb
Caleb
Alex Busenius wrote:
Unfortunately, using POST requests instead of GET requests is not enough. It will not prevent attacks that use forms and/or JavaScript to generate POST requests.
Alex
On 03/09/2010 02:48 PM, Caleb James DeLisle wrote:
I had thought about proposing this myself but decided against it because it seems to me like a workaround for problems which can be solved in other ways.
Suppose we were to add a check to the actions which alter data which made sure the request method was 'post' and made it configurable in one of the configuration files? We would have to look over the default skins for incorrect links and leave the configuration option off by default for backward compatibility at least until the next major version but we could provide wiki operators the ability to prevent CSRF.
Caleb
_______________________________________________ devs mailing list devs@xwiki.org http://lists.xwiki.org/mailman/listinfo/devs
_______________________________________________ devs mailing list devs@xwiki.org http://lists.xwiki.org/mailman/listinfo/devs
devs mailing list devs@xwiki.org http://lists.xwiki.org/mailman/listinfo/devs
_______________________________________________ devs mailing list devs@xwiki.org http://lists.xwiki.org/mailman/listinfo/devs
Marius Dumitru Florea wrote:
Hi Caleb,
Caleb James DeLisle wrote:
I don't want this proposal to die because of unnecessary noise which I introduced, I have thought about it and I am in agreement with the general idea of sending the user a hash which must be returned with the post in order for the data to be saved.
I don't like adding code to xwiki-core so I suggest this be made into a component. We would need 2 functions: String getToken() boolean isTokenValid(String token)
getToken uses org.xwiki.bridge.DocumentAccessBridge.getCurrentUser() to get the user who called it and the user name is stored in a HashMap of <String, String> with a random string of text.
If getToken finds a token already in the map, it returns that token (so it may be called multiple times in the generation of a page)
So the token is the same for consecutive (GET) requests coming from the same user?
isTokenValid checks the current user against the token then removes the entry from the HashMap so the token may not be reused.
What happens if the user opens in edit mode two different pages? Isn't the second save invalidated by the first save?
Good point I missed. I would have to have a script to disable such an onerous 'feature' :) I guess it will only work if a single number is valid basically forever. I wish components had access to the Request, Response and Session so it could expire on logout. Caleb
Thanks, Marius
If a configuration parameter is specified to disable the component, getToken returns "" and isTokenValid returns true.
WDYT?
Caleb
Caleb James DeLisle wrote:
Sergiu Dumitriu wrote:
On 03/10/2010 07:44 PM, Caleb James DeLisle wrote:
Take a look at the "sammy is my hero" worm, myspace sent a hash to the user like the one you propose, the worm made the required get request to get the hash, then made the post along with the hash. What prevents javascript from opening the page with the hash in an iframe and then reading in the iframe to get the hash, then creating a form with the required data and posting it to the save action?
If we were to combine a requirement for post requests with checking of the referrer header, then we would block links, forms and javascript based attacks leaving only an attack through older versions of flash which support referrer forgery and at this point the difficulty of the attack becomes such that we need to consider a wider array of attack vectors. Sammy also required that XSS is enabled.
Protecting from attacks originating in the wiki is kind of impossible at the moment, since JS can be inserted anywhere, and there's no (nice) way to prevent attacks from JS inside the application. As long as JS can be inserted, an attacker can do all the steps that the client would do to perform an action.
The secret token works as a prevention mechanism when the attack comes from another site because the browser security model prevents the attack code to read the form. I just did a few tests on iframes and I was wrong, they do have good same origin policy.
Caleb
Caleb
Alex Busenius wrote:
Unfortunately, using POST requests instead of GET requests is not enough. It will not prevent attacks that use forms and/or JavaScript to generate POST requests.
Alex
On 03/09/2010 02:48 PM, Caleb James DeLisle wrote: > I had thought about proposing this myself but decided against it because it seems > to me like a workaround for problems which can be solved in other ways. > > Suppose we were to add a check to the actions which alter data which made sure the request method > was 'post' and made it configurable in one of the configuration files? We would have > to look over the default skins for incorrect links and leave the configuration > option off by default for backward compatibility at least until the next major version > but we could provide wiki operators the ability to prevent CSRF. > > Caleb > _______________________________________________ devs mailing list devs@xwiki.org http://lists.xwiki.org/mailman/listinfo/devs
_______________________________________________ devs mailing list devs@xwiki.org http://lists.xwiki.org/mailman/listinfo/devs
devs mailing list devs@xwiki.org http://lists.xwiki.org/mailman/listinfo/devs
_______________________________________________ devs mailing list devs@xwiki.org http://lists.xwiki.org/mailman/listinfo/devs
devs mailing list devs@xwiki.org http://lists.xwiki.org/mailman/listinfo/devs
On 03/16/2010 10:23 AM, Caleb James DeLisle wrote:
Marius Dumitru Florea wrote:
Hi Caleb,
Caleb James DeLisle wrote:
I don't want this proposal to die because of unnecessary noise which I introduced, I have thought about it and I am in agreement with the general idea of sending the user a hash which must be returned with the post in order for the data to be saved.
I don't like adding code to xwiki-core so I suggest this be made into a component. We would need 2 functions: String getToken() boolean isTokenValid(String token)
getToken uses org.xwiki.bridge.DocumentAccessBridge.getCurrentUser() to get the user who called it and the user name is stored in a HashMap of <String, String> with a random string of text.
If getToken finds a token already in the map, it returns that token (so it may be called multiple times in the generation of a page)
So the token is the same for consecutive (GET) requests coming from the same user?
isTokenValid checks the current user against the token then removes the entry from the HashMap so the token may not be reused.
What happens if the user opens in edit mode two different pages? Isn't the second save invalidated by the first save?
Good point I missed. I would have to have a script to disable such an onerous 'feature' :) I guess it will only work if a single number is valid basically forever. I wish components had access to the Request, Response and Session so it could expire on logout.
What if this map would store a mapping (user + url) -> token, or (user + reason) -> token, where "reason" would be some description of the intended change like "edit:Main.Test" or "rights:SomeUser+comment-edit"? getToken would return different tokens for different pages/"reasons" and isTokenValid would need to provide the same url/"reason" for check to succeed.
Caleb
Thanks, Marius
If a configuration parameter is specified to disable the component, getToken returns "" and isTokenValid returns true.
WDYT?
Caleb
Caleb James DeLisle wrote:
Sergiu Dumitriu wrote:
On 03/10/2010 07:44 PM, Caleb James DeLisle wrote:
Take a look at the "sammy is my hero" worm, myspace sent a hash to the user like the one you propose, the worm made the required get request to get the hash, then made the post along with the hash. What prevents javascript from opening the page with the hash in an iframe and then reading in the iframe to get the hash, then creating a form with the required data and posting it to the save action?
If we were to combine a requirement for post requests with checking of the referrer header, then we would block links, forms and javascript based attacks leaving only an attack through older versions of flash which support referrer forgery and at this point the difficulty of the attack becomes such that we need to consider a wider array of attack vectors. Sammy also required that XSS is enabled.
Protecting from attacks originating in the wiki is kind of impossible at the moment, since JS can be inserted anywhere, and there's no (nice) way to prevent attacks from JS inside the application. As long as JS can be inserted, an attacker can do all the steps that the client would do to perform an action.
The secret token works as a prevention mechanism when the attack comes from another site because the browser security model prevents the attack code to read the form. I just did a few tests on iframes and I was wrong, they do have good same origin policy.
Caleb
Caleb
Alex Busenius wrote: > Unfortunately, using POST requests instead of GET requests is not > enough. It will not prevent attacks that use forms and/or JavaScript to > generate POST requests. > > Alex > > > On 03/09/2010 02:48 PM, Caleb James DeLisle wrote: >> I had thought about proposing this myself but decided against it because it seems >> to me like a workaround for problems which can be solved in other ways. >> >> Suppose we were to add a check to the actions which alter data which made sure the request method >> was 'post' and made it configurable in one of the configuration files? We would have >> to look over the default skins for incorrect links and leave the configuration >> option off by default for backward compatibility at least until the next major version >> but we could provide wiki operators the ability to prevent CSRF. >> >> Caleb >> > _______________________________________________ > devs mailing list > devs@xwiki.org > http://lists.xwiki.org/mailman/listinfo/devs > _______________________________________________ devs mailing list devs@xwiki.org http://lists.xwiki.org/mailman/listinfo/devs
devs mailing list devs@xwiki.org http://lists.xwiki.org/mailman/listinfo/devs
_______________________________________________ devs mailing list devs@xwiki.org http://lists.xwiki.org/mailman/listinfo/devs
devs mailing list devs@xwiki.org http://lists.xwiki.org/mailman/listinfo/devs
_______________________________________________ devs mailing list devs@xwiki.org http://lists.xwiki.org/mailman/listinfo/devs
Alex Busenius wrote:
On 03/16/2010 10:23 AM, Caleb James DeLisle wrote:
Marius Dumitru Florea wrote:
Hi Caleb,
Caleb James DeLisle wrote:
I don't want this proposal to die because of unnecessary noise which I introduced, I have thought about it and I am in agreement with the general idea of sending the user a hash which must be returned with the post in order for the data to be saved.
I don't like adding code to xwiki-core so I suggest this be made into a component. We would need 2 functions: String getToken() boolean isTokenValid(String token)
getToken uses org.xwiki.bridge.DocumentAccessBridge.getCurrentUser() to get the user who called it and the user name is stored in a HashMap of <String, String> with a random string of text.
If getToken finds a token already in the map, it returns that token (so it may be called multiple times in the generation of a page) So the token is the same for consecutive (GET) requests coming from the same user?
isTokenValid checks the current user against the token then removes the entry from the HashMap so the token may not be reused. What happens if the user opens in edit mode two different pages? Isn't the second save invalidated by the first save? Good point I missed. I would have to have a script to disable such an onerous 'feature' :) I guess it will only work if a single number is valid basically forever. I wish components had access to the Request, Response and Session so it could expire on logout.
What if this map would store a mapping (user + url) -> token, URL sounds like a good idea, what are the chances that a user will be editing the same page in 2 windows? Even if they are, editing the same page will cause past changes to be lost. Perhaps if the token fails they should get a page with a warning message and an opportunity to save anyway. We can compare the URL to the referrer header which makes life easy (we would need access to the request but I think this is coming soon.)
or (user + reason) -> token, where "reason" would be some description of the intended change like "edit:Main.Test" or "rights:SomeUser+comment-edit"? This idea sounds like it would require a lot of extra infrastructure, maybe I am not seeing it right.
getToken would return different tokens for different pages/"reasons" and isTokenValid would need to provide the same url/"reason" for check to succeed.
Caleb
Thanks, Marius
If a configuration parameter is specified to disable the component, getToken returns "" and isTokenValid returns true.
WDYT?
Caleb
Caleb James DeLisle wrote:
Sergiu Dumitriu wrote:
On 03/10/2010 07:44 PM, Caleb James DeLisle wrote: > Take a look at the "sammy is my hero" worm, myspace sent a hash to the user like the one you propose, > the worm made the required get request to get the hash, then made the post along with the hash. > What prevents javascript from opening the page with the hash in an iframe and then reading in the iframe > to get the hash, then creating a form with the required data and posting it to the save action? > > If we were to combine a requirement for post requests with checking of the referrer header, then we > would block links, forms and javascript based attacks leaving only an attack through older versions > of flash which support referrer forgery and at this point the difficulty of the attack becomes such that > we need to consider a wider array of attack vectors. Sammy also required that XSS is enabled.
Protecting from attacks originating in the wiki is kind of impossible at the moment, since JS can be inserted anywhere, and there's no (nice) way to prevent attacks from JS inside the application. As long as JS can be inserted, an attacker can do all the steps that the client would do to perform an action.
The secret token works as a prevention mechanism when the attack comes from another site because the browser security model prevents the attack code to read the form. I just did a few tests on iframes and I was wrong, they do have good same origin policy.
Caleb
> Caleb > > > Alex Busenius wrote: >> Unfortunately, using POST requests instead of GET requests is not >> enough. It will not prevent attacks that use forms and/or JavaScript to >> generate POST requests. >> >> Alex >> >> >> On 03/09/2010 02:48 PM, Caleb James DeLisle wrote: >>> I had thought about proposing this myself but decided against it because it seems >>> to me like a workaround for problems which can be solved in other ways. >>> >>> Suppose we were to add a check to the actions which alter data which made sure the request method >>> was 'post' and made it configurable in one of the configuration files? We would have >>> to look over the default skins for incorrect links and leave the configuration >>> option off by default for backward compatibility at least until the next major version >>> but we could provide wiki operators the ability to prevent CSRF. >>> >>> Caleb >>> >> _______________________________________________ >> devs mailing list >> devs@xwiki.org >> http://lists.xwiki.org/mailman/listinfo/devs >> > _______________________________________________ > devs mailing list > devs@xwiki.org > http://lists.xwiki.org/mailman/listinfo/devs >
devs mailing list devs@xwiki.org http://lists.xwiki.org/mailman/listinfo/devs
_______________________________________________ devs mailing list devs@xwiki.org http://lists.xwiki.org/mailman/listinfo/devs
devs mailing list devs@xwiki.org http://lists.xwiki.org/mailman/listinfo/devs
_______________________________________________ devs mailing list devs@xwiki.org http://lists.xwiki.org/mailman/listinfo/devs
_______________________________________________ devs mailing list devs@xwiki.org http://lists.xwiki.org/mailman/listinfo/devs
This message seems to have disappeared, resending... Alex Busenius wrote:
On 03/16/2010 10:23 AM, Caleb James DeLisle wrote:
Marius Dumitru Florea wrote:
Hi Caleb,
Caleb James DeLisle wrote:
I don't want this proposal to die because of unnecessary noise which I introduced, I have thought about it and I am in agreement with the general idea of sending the user a hash which must be returned with the post in order for the data to be saved.
I don't like adding code to xwiki-core so I suggest this be made into a component. We would need 2 functions: String getToken() boolean isTokenValid(String token)
getToken uses org.xwiki.bridge.DocumentAccessBridge.getCurrentUser() to get the user who called it and the user name is stored in a HashMap of <String, String> with a random string of text.
If getToken finds a token already in the map, it returns that token (so it may be called multiple times in the generation of a page) So the token is the same for consecutive (GET) requests coming from the same user?
isTokenValid checks the current user against the token then removes the entry from the HashMap so the token may not be reused. What happens if the user opens in edit mode two different pages? Isn't the second save invalidated by the first save? Good point I missed. I would have to have a script to disable such an onerous 'feature' :) I guess it will only work if a single number is valid basically forever. I wish components had access to the Request, Response and Session so it could expire on logout.
What if this map would store a mapping (user + url) -> token, URL sounds like a good idea, what are the chances that a user will be editing the same page in 2 windows? Even if they are, editing the same page will cause past changes to be lost. Perhaps if the token fails they should get a page with a warning message and an opportunity to save anyway. We can compare the URL to the referrer header which makes life easy (we would need access to the request but I think this is coming soon.)
or (user + reason) -> token, where "reason" would be some description of the intended change like "edit:Main.Test" or "rights:SomeUser+comment-edit"? This idea sounds like it would require a lot of extra infrastructure, maybe I am not seeing it right.
getToken would return different tokens for different pages/"reasons" and isTokenValid would need to provide the same url/"reason" for check to succeed.
Caleb
Thanks, Marius
If a configuration parameter is specified to disable the component, getToken returns "" and isTokenValid returns true.
WDYT?
Caleb
Caleb James DeLisle wrote:
Sergiu Dumitriu wrote:
On 03/10/2010 07:44 PM, Caleb James DeLisle wrote: > Take a look at the "sammy is my hero" worm, myspace sent a hash to the user like the one you propose, > the worm made the required get request to get the hash, then made the post along with the hash. > What prevents javascript from opening the page with the hash in an iframe and then reading in the iframe > to get the hash, then creating a form with the required data and posting it to the save action? > > If we were to combine a requirement for post requests with checking of the referrer header, then we > would block links, forms and javascript based attacks leaving only an attack through older versions > of flash which support referrer forgery and at this point the difficulty of the attack becomes such that > we need to consider a wider array of attack vectors. Sammy also required that XSS is enabled.
Protecting from attacks originating in the wiki is kind of impossible at the moment, since JS can be inserted anywhere, and there's no (nice) way to prevent attacks from JS inside the application. As long as JS can be inserted, an attacker can do all the steps that the client would do to perform an action.
The secret token works as a prevention mechanism when the attack comes from another site because the browser security model prevents the attack code to read the form. I just did a few tests on iframes and I was wrong, they do have good same origin policy.
Caleb
> Caleb > > > Alex Busenius wrote: >> Unfortunately, using POST requests instead of GET requests is not >> enough. It will not prevent attacks that use forms and/or JavaScript to >> generate POST requests. >> >> Alex >> >> >> On 03/09/2010 02:48 PM, Caleb James DeLisle wrote: >>> I had thought about proposing this myself but decided against it because it seems >>> to me like a workaround for problems which can be solved in other ways. >>> >>> Suppose we were to add a check to the actions which alter data which made sure the request method >>> was 'post' and made it configurable in one of the configuration files? We would have >>> to look over the default skins for incorrect links and leave the configuration >>> option off by default for backward compatibility at least until the next major version >>> but we could provide wiki operators the ability to prevent CSRF. >>> >>> Caleb >>> >> _______________________________________________ >> devs mailing list >> devs@xwiki.org >> http://lists.xwiki.org/mailman/listinfo/devs >> > _______________________________________________ > devs mailing list > devs@xwiki.org > http://lists.xwiki.org/mailman/listinfo/devs >
devs mailing list devs@xwiki.org http://lists.xwiki.org/mailman/listinfo/devs
_______________________________________________ devs mailing list devs@xwiki.org http://lists.xwiki.org/mailman/listinfo/devs
devs mailing list devs@xwiki.org http://lists.xwiki.org/mailman/listinfo/devs
_______________________________________________ devs mailing list devs@xwiki.org http://lists.xwiki.org/mailman/listinfo/devs
_______________________________________________ devs mailing list devs@xwiki.org http://lists.xwiki.org/mailman/listinfo/devs
On 03/18/2010 05:57 AM, Caleb James DeLisle wrote:
This message seems to have disappeared, resending...
Alex Busenius wrote:
On 03/16/2010 10:23 AM, Caleb James DeLisle wrote:
Marius Dumitru Florea wrote:
Hi Caleb,
Caleb James DeLisle wrote:
I don't want this proposal to die because of unnecessary noise which I introduced, I have thought about it and I am in agreement with the general idea of sending the user a hash which must be returned with the post in order for the data to be saved.
I don't like adding code to xwiki-core so I suggest this be made into a component. We would need 2 functions: String getToken() boolean isTokenValid(String token)
getToken uses org.xwiki.bridge.DocumentAccessBridge.getCurrentUser() to get the user who called it and the user name is stored in a HashMap of <String, String> with a random string of text.
If getToken finds a token already in the map, it returns that token (so it may be called multiple times in the generation of a page) So the token is the same for consecutive (GET) requests coming from the same user?
isTokenValid checks the current user against the token then removes the entry from the HashMap so the token may not be reused. What happens if the user opens in edit mode two different pages? Isn't the second save invalidated by the first save? Good point I missed. I would have to have a script to disable such an onerous 'feature' :) I guess it will only work if a single number is valid basically forever. I wish components had access to the Request, Response and Session so it could expire on logout.
What if this map would store a mapping (user + url) -> token, URL sounds like a good idea, what are the chances that a user will be editing the same page in 2 windows? Even if they are, editing the same page will cause past changes to be lost. Perhaps if the token fails they should get a page with a warning message and an opportunity to save anyway.
Editing the same page in two windows is probably not common, but the behavior would change. Currently, both saves work and _both_ are recorded in the history in the order they were saved. With the tokens the editor that was opened first would get an access denied on save, and the one opened last would work. I'm not sure how we can go back to editor and refresh only the token but leave the modified text. And the natural reaction of a user would probably be to hit the back button in browser, which would restore the editor page with the invalid token.
We can compare the URL to the referrer header which makes life easy (we would need access to the request but I think this is coming soon.)
True, once we have access to the request we could easily add referrer header checking.
or (user + reason) -> token, where "reason" would be some description of the intended change like "edit:Main.Test" or "rights:SomeUser+comment-edit"? This idea sounds like it would require a lot of extra infrastructure, maybe I am not seeing it right.
No, the "reason" would contain only the important part of the things that are currently usually in the URL, like document name and action.
From the viewpoint of token component the exact content doesn't matter, it should just contain enough information to differentiate editing of different things.
The reason for this idea is that we would need to give the same URL to both getToken and isTokenValid as an argument, but those methods are usually called from totally different places. So I think it is easier to give the (somewhat simplified) reason instead of trying to come up with the same URL after several redirects. For example, URLS for editing and deleting a page clearly differ in the action part (/delete/Main/WebHome vs. /save/Main/Webhome), but most administrative tasks go to /admin/XWiki/XWikiPreferences, are redirected to saverights.vm and only differ in the query part of the URL. Pages can also be edited over /preview/... with correct parameters. Changing access rights sometimes use /save/... as URL, etc. WDYT? Alex
getToken would return different tokens for different pages/"reasons" and isTokenValid would need to provide the same url/"reason" for check to succeed.
Caleb
Thanks, Marius
If a configuration parameter is specified to disable the component, getToken returns "" and isTokenValid returns true.
WDYT?
Caleb
Caleb James DeLisle wrote:
Sergiu Dumitriu wrote: > On 03/10/2010 07:44 PM, Caleb James DeLisle wrote: >> Take a look at the "sammy is my hero" worm, myspace sent a hash to the user like the one you propose, >> the worm made the required get request to get the hash, then made the post along with the hash. >> What prevents javascript from opening the page with the hash in an iframe and then reading in the iframe >> to get the hash, then creating a form with the required data and posting it to the save action? >> >> If we were to combine a requirement for post requests with checking of the referrer header, then we >> would block links, forms and javascript based attacks leaving only an attack through older versions >> of flash which support referrer forgery and at this point the difficulty of the attack becomes such that >> we need to consider a wider array of attack vectors. > Sammy also required that XSS is enabled. > > Protecting from attacks originating in the wiki is kind of impossible at > the moment, since JS can be inserted anywhere, and there's no (nice) way > to prevent attacks from JS inside the application. As long as JS can be > inserted, an attacker can do all the steps that the client would do to > perform an action. > > The secret token works as a prevention mechanism when the attack comes > from another site because the browser security model prevents the attack > code to read the form. I just did a few tests on iframes and I was wrong, they do have good same origin policy.
Caleb
>> Caleb >> >> >> Alex Busenius wrote: >>> Unfortunately, using POST requests instead of GET requests is not >>> enough. It will not prevent attacks that use forms and/or JavaScript to >>> generate POST requests. >>> >>> Alex >>> >>> >>> On 03/09/2010 02:48 PM, Caleb James DeLisle wrote: >>>> I had thought about proposing this myself but decided against it because it seems >>>> to me like a workaround for problems which can be solved in other ways. >>>> >>>> Suppose we were to add a check to the actions which alter data which made sure the request method >>>> was 'post' and made it configurable in one of the configuration files? We would have >>>> to look over the default skins for incorrect links and leave the configuration >>>> option off by default for backward compatibility at least until the next major version >>>> but we could provide wiki operators the ability to prevent CSRF. >>>> >>>> Caleb >>>> >>> _______________________________________________ >>> devs mailing list >>> devs@xwiki.org >>> http://lists.xwiki.org/mailman/listinfo/devs >>>
Hi Alex, Alex Busenius wrote:
On 03/18/2010 05:57 AM, Caleb James DeLisle wrote:
This message seems to have disappeared, resending...
Alex Busenius wrote:
On 03/16/2010 10:23 AM, Caleb James DeLisle wrote:
Marius Dumitru Florea wrote:
Hi Caleb,
Caleb James DeLisle wrote:
I don't want this proposal to die because of unnecessary noise which I introduced, I have thought about it and I am in agreement with the general idea of sending the user a hash which must be returned with the post in order for the data to be saved.
I don't like adding code to xwiki-core so I suggest this be made into a component. We would need 2 functions: String getToken() boolean isTokenValid(String token)
getToken uses org.xwiki.bridge.DocumentAccessBridge.getCurrentUser() to get the user who called it and the user name is stored in a HashMap of <String, String> with a random string of text.
If getToken finds a token already in the map, it returns that token (so it may be called multiple times in the generation of a page) So the token is the same for consecutive (GET) requests coming from the same user?
isTokenValid checks the current user against the token then removes the entry from the HashMap so the token may not be reused. What happens if the user opens in edit mode two different pages? Isn't the second save invalidated by the first save? Good point I missed. I would have to have a script to disable such an onerous 'feature' :) I guess it will only work if a single number is valid basically forever. I wish components had access to the Request, Response and Session so it could expire on logout. What if this map would store a mapping (user + url) -> token, URL sounds like a good idea, what are the chances that a user will be editing the same page in 2 windows? Even if they are, editing the same page will cause past changes to be lost. Perhaps if the token fails they should get a page with a warning message and an opportunity to save anyway.
Editing the same page in two windows is probably not common, but the behavior would change. Currently, both saves work and _both_ are recorded in the history in the order they were saved. With the tokens the editor that was opened first would get an access denied on save, and the one opened last would work. I'm not sure how we can go back to editor and refresh only the token but leave the modified text. And the natural reaction of a user would probably be to hit the back button in browser, which would restore the editor page with the invalid token.
Maybe we can return the user to the edit page with a _new_ token and the submitted content when the received token is invalid, asking the user for a confirmation and explaining her/him why the confirmation is needed. This way the user can retry saving the content (this step can repeat over and over if "she/he" keeps opening other tabs and saving the page there instead) or continue editing. Does this still prevent the attack? Thanks, Marius
We can compare the URL to the referrer header which makes life easy (we would need access to the request but I think this is coming soon.)
True, once we have access to the request we could easily add referrer header checking.
or (user + reason) -> token, where "reason" would be some description of the intended change like "edit:Main.Test" or "rights:SomeUser+comment-edit"? This idea sounds like it would require a lot of extra infrastructure, maybe I am not seeing it right.
No, the "reason" would contain only the important part of the things that are currently usually in the URL, like document name and action. From the viewpoint of token component the exact content doesn't matter, it should just contain enough information to differentiate editing of different things.
The reason for this idea is that we would need to give the same URL to both getToken and isTokenValid as an argument, but those methods are usually called from totally different places. So I think it is easier to give the (somewhat simplified) reason instead of trying to come up with the same URL after several redirects.
For example, URLS for editing and deleting a page clearly differ in the action part (/delete/Main/WebHome vs. /save/Main/Webhome), but most administrative tasks go to /admin/XWiki/XWikiPreferences, are redirected to saverights.vm and only differ in the query part of the URL. Pages can also be edited over /preview/... with correct parameters. Changing access rights sometimes use /save/... as URL, etc.
WDYT?
Alex
getToken would return different tokens for different pages/"reasons" and isTokenValid would need to provide the same url/"reason" for check to succeed.
Caleb
Thanks, Marius
If a configuration parameter is specified to disable the component, getToken returns "" and isTokenValid returns true.
WDYT?
Caleb
Caleb James DeLisle wrote: > Sergiu Dumitriu wrote: >> On 03/10/2010 07:44 PM, Caleb James DeLisle wrote: >>> Take a look at the "sammy is my hero" worm, myspace sent a hash to the user like the one you propose, >>> the worm made the required get request to get the hash, then made the post along with the hash. >>> What prevents javascript from opening the page with the hash in an iframe and then reading in the iframe >>> to get the hash, then creating a form with the required data and posting it to the save action? >>> >>> If we were to combine a requirement for post requests with checking of the referrer header, then we >>> would block links, forms and javascript based attacks leaving only an attack through older versions >>> of flash which support referrer forgery and at this point the difficulty of the attack becomes such that >>> we need to consider a wider array of attack vectors. >> Sammy also required that XSS is enabled. >> >> Protecting from attacks originating in the wiki is kind of impossible at >> the moment, since JS can be inserted anywhere, and there's no (nice) way >> to prevent attacks from JS inside the application. As long as JS can be >> inserted, an attacker can do all the steps that the client would do to >> perform an action. >> >> The secret token works as a prevention mechanism when the attack comes >> from another site because the browser security model prevents the attack >> code to read the form. > I just did a few tests on iframes and I was wrong, they do have good same origin policy. > > Caleb > >>> Caleb >>> >>> >>> Alex Busenius wrote: >>>> Unfortunately, using POST requests instead of GET requests is not >>>> enough. It will not prevent attacks that use forms and/or JavaScript to >>>> generate POST requests. >>>> >>>> Alex >>>> >>>> >>>> On 03/09/2010 02:48 PM, Caleb James DeLisle wrote: >>>>> I had thought about proposing this myself but decided against it because it seems >>>>> to me like a workaround for problems which can be solved in other ways. >>>>> >>>>> Suppose we were to add a check to the actions which alter data which made sure the request method >>>>> was 'post' and made it configurable in one of the configuration files? We would have >>>>> to look over the default skins for incorrect links and leave the configuration >>>>> option off by default for backward compatibility at least until the next major version >>>>> but we could provide wiki operators the ability to prevent CSRF. >>>>> >>>>> Caleb >>>>> >>>> _______________________________________________ >>>> devs mailing list >>>> devs@xwiki.org >>>> http://lists.xwiki.org/mailman/listinfo/devs >>>>
devs mailing list devs@xwiki.org http://lists.xwiki.org/mailman/listinfo/devs
Hi Marius, On 03/18/2010 02:29 PM, Marius Dumitru Florea wrote:
Hi Alex,
Alex Busenius wrote:
On 03/18/2010 05:57 AM, Caleb James DeLisle wrote:
This message seems to have disappeared, resending...
Alex Busenius wrote:
On 03/16/2010 10:23 AM, Caleb James DeLisle wrote:
Marius Dumitru Florea wrote:
Hi Caleb,
Caleb James DeLisle wrote: > I don't want this proposal to die because of unnecessary noise which I introduced, > I have thought about it and I am in agreement with the general idea of sending the user a hash which > must be returned with the post in order for the data to be saved. > > I don't like adding code to xwiki-core so I suggest this be made into a component. > We would need 2 functions: > String getToken() > boolean isTokenValid(String token) > > getToken uses org.xwiki.bridge.DocumentAccessBridge.getCurrentUser() to get the user who called it > and the user name is stored in a HashMap of <String, String> with a random string of text. > > If getToken finds a token already in the map, it returns that token (so it may be called multiple times > in the generation of a page) So the token is the same for consecutive (GET) requests coming from the same user?
> isTokenValid checks the current user against the token then removes the entry from the HashMap so the token > may not be reused. What happens if the user opens in edit mode two different pages? Isn't the second save invalidated by the first save? Good point I missed. I would have to have a script to disable such an onerous 'feature' :) I guess it will only work if a single number is valid basically forever. I wish components had access to the Request, Response and Session so it could expire on logout. What if this map would store a mapping (user + url) -> token, URL sounds like a good idea, what are the chances that a user will be editing the same page in 2 windows? Even if they are, editing the same page will cause past changes to be lost. Perhaps if the token fails they should get a page with a warning message and an opportunity to save anyway.
Editing the same page in two windows is probably not common, but the behavior would change. Currently, both saves work and _both_ are recorded in the history in the order they were saved. With the tokens the editor that was opened first would get an access denied on save, and the one opened last would work. I'm not sure how we can go back to editor and refresh only the token but leave the modified text. And the natural reaction of a user would probably be to hit the back button in browser, which would restore the editor page with the invalid token.
Maybe we can return the user to the edit page with a _new_ token and the submitted content when the received token is invalid, asking the user for a confirmation and explaining her/him why the confirmation is needed. This way the user can retry saving the content (this step can repeat over and over if "she/he" keeps opening other tabs and saving the page there instead) or continue editing.
Does this still prevent the attack?
Yes, as long as the modified content is just redirected back to the user and not saved until the token check succeeds. Alex
Thanks, Marius
We can compare the URL to the referrer header which makes life easy (we would need access to the request but I think this is coming soon.)
True, once we have access to the request we could easily add referrer header checking.
or (user + reason) -> token, where "reason" would be some description of the intended change like "edit:Main.Test" or "rights:SomeUser+comment-edit"? This idea sounds like it would require a lot of extra infrastructure, maybe I am not seeing it right.
No, the "reason" would contain only the important part of the things that are currently usually in the URL, like document name and action. From the viewpoint of token component the exact content doesn't matter, it should just contain enough information to differentiate editing of different things.
The reason for this idea is that we would need to give the same URL to both getToken and isTokenValid as an argument, but those methods are usually called from totally different places. So I think it is easier to give the (somewhat simplified) reason instead of trying to come up with the same URL after several redirects.
For example, URLS for editing and deleting a page clearly differ in the action part (/delete/Main/WebHome vs. /save/Main/Webhome), but most administrative tasks go to /admin/XWiki/XWikiPreferences, are redirected to saverights.vm and only differ in the query part of the URL. Pages can also be edited over /preview/... with correct parameters. Changing access rights sometimes use /save/... as URL, etc.
WDYT?
Alex
getToken would return different tokens for different pages/"reasons" and isTokenValid would need to provide the same url/"reason" for check to succeed.
Caleb
Thanks, Marius
> If a configuration parameter is specified to disable the component, getToken returns "" and isTokenValid > returns true. > > WDYT? > > Caleb > > > Caleb James DeLisle wrote: >> Sergiu Dumitriu wrote: >>> On 03/10/2010 07:44 PM, Caleb James DeLisle wrote: >>>> Take a look at the "sammy is my hero" worm, myspace sent a hash to the user like the one you propose, >>>> the worm made the required get request to get the hash, then made the post along with the hash. >>>> What prevents javascript from opening the page with the hash in an iframe and then reading in the iframe >>>> to get the hash, then creating a form with the required data and posting it to the save action? >>>> >>>> If we were to combine a requirement for post requests with checking of the referrer header, then we >>>> would block links, forms and javascript based attacks leaving only an attack through older versions >>>> of flash which support referrer forgery and at this point the difficulty of the attack becomes such that >>>> we need to consider a wider array of attack vectors. >>> Sammy also required that XSS is enabled. >>> >>> Protecting from attacks originating in the wiki is kind of impossible at >>> the moment, since JS can be inserted anywhere, and there's no (nice) way >>> to prevent attacks from JS inside the application. As long as JS can be >>> inserted, an attacker can do all the steps that the client would do to >>> perform an action. >>> >>> The secret token works as a prevention mechanism when the attack comes >>> from another site because the browser security model prevents the attack >>> code to read the form. >> I just did a few tests on iframes and I was wrong, they do have good same origin policy. >> >> Caleb >> >>>> Caleb >>>> >>>> >>>> Alex Busenius wrote: >>>>> Unfortunately, using POST requests instead of GET requests is not >>>>> enough. It will not prevent attacks that use forms and/or JavaScript to >>>>> generate POST requests. >>>>> >>>>> Alex >>>>> >>>>> >>>>> On 03/09/2010 02:48 PM, Caleb James DeLisle wrote: >>>>>> I had thought about proposing this myself but decided against it because it seems >>>>>> to me like a workaround for problems which can be solved in other ways. >>>>>> >>>>>> Suppose we were to add a check to the actions which alter data which made sure the request method >>>>>> was 'post' and made it configurable in one of the configuration files? We would have >>>>>> to look over the default skins for incorrect links and leave the configuration >>>>>> option off by default for backward compatibility at least until the next major version >>>>>> but we could provide wiki operators the ability to prevent CSRF. >>>>>> >>>>>> Caleb >>>>>> >>>>> _______________________________________________ >>>>> devs mailing list >>>>> devs@xwiki.org >>>>> http://lists.xwiki.org/mailman/listinfo/devs >>>>>
devs mailing list devs@xwiki.org http://lists.xwiki.org/mailman/listinfo/devs
_______________________________________________ devs mailing list devs@xwiki.org http://lists.xwiki.org/mailman/listinfo/devs
[i forgot to send this earlier]
Good point I missed. I would have to have a script to disable such an onerous 'feature' :)
I guess it will only work if a single number is valid basically forever. I
wish components had access to the
Request, Response and Session so it could expire on logout. Caleb Unless I'm misunderstanding, how can you protect against any form of replay attack if the token remains the same each time? Protection against replay attacks is why such tokens are usually nonces or "one time pads". More practically, you can use a signed timestamp, in whatever form, e.g. my prior suggestion of crypto-cookes+SSL, or you can add an exrtra prop in core. Either way, both implementations time-out or cannot be reused much because the server encodes a timestamp, and encrypts&signs it with it's own secret key. While you're at it you can also have the server self-sign a bitmap of what privileges are available. On submission/post, only those privileges would be available to the executing code, due to the contents of the token/key/crypto-cookie's "privileges bitmap." The script would be executed in context of (1) validity of overall signature (2) valid signed and non expired timestamp (3) access granted in "privileges bitmap", e.g. programming rights, read-, and write-access to spaces (which can all be enumerated in a long string as bitmap). If the timestamp is expired, you could kick into a part of the app that checks that the user is logged in (in browser) through other means (hopefully uninstrusively) and then issues another token, with fresh timestamp as an automatic resubmission. By uninstrusive, I mean, you want the ticket to only be valid for a few seconds, but the user may take minutes, or hours to hit "submit" and shouldn't need to explicitly re-validate or re-auth with a user/password again (e.g. check for auth in cookie, client-certificate, etc). In any case, any time the server actually accepts a submission, it's because the timestamp on a short lived transaction was valid/signed. Anytime anything of "authority" needs to be performed, it checks the privileges bitmap to see if it was initially allowed-for, by the server, and by the valid code-stream (the one with access to the server key for signing/encrypting the bitmap)... That's a fair set of "checks and balances" against site-hacking. Niels http://nielsmayer.com
Hi Niels, On 03/19/2010 09:47 PM, Niels Mayer wrote:
[i forgot to send this earlier]
Good point I missed. I would have to have a script to disable such an onerous 'feature' :)
I guess it will only work if a single number is valid basically forever. I
wish components had access to the
Request, Response and Session so it could expire on logout.
Caleb
Unless I'm misunderstanding, how can you protect against any form of replay attack if the token remains the same each time?
You can't, but CSRF is *not* a replay attack. You are thinking about way too involved attack scenarios and powerful attackers, try the simple things first :) Take a look here for example: http://www.owasp.org/index.php/Cross-Site_Request_Forgery_%28CSRF%29
Protection against replay attacks is why such tokens are usually nonces or "one time pads". More practically, you can use a signed timestamp, in whatever form, e.g. my prior suggestion of crypto-cookes+SSL, or you can add an exrtra prop in core. Either way, both implementations time-out or cannot be reused much because the server encodes a timestamp, and encrypts&signs it with it's own secret key.
While you're at it you can also have the server self-sign a bitmap of what privileges are available. On submission/post, only those privileges would be available to the executing code, due to the contents of the token/key/crypto-cookie's "privileges bitmap."
The script would be executed in context of (1) validity of overall signature (2) valid signed and non expired timestamp (3) access granted in "privileges bitmap", e.g. programming rights, read-, and write-access to spaces (which can all be enumerated in a long string as bitmap). If the timestamp is expired, you could kick into a part of the app that checks that the user is logged in (in browser) through other means (hopefully uninstrusively) and then issues another token, with fresh timestamp as an automatic resubmission. By uninstrusive, I mean, you want the ticket to only be valid for a few seconds, but the user may take minutes, or hours to hit "submit" and shouldn't need to explicitly re-validate or re-auth with a user/password again (e.g. check for auth in cookie, client-certificate, etc).
In any case, any time the server actually accepts a submission, it's because the timestamp on a short lived transaction was valid/signed. Anytime anything of "authority" needs to be performed, it checks the privileges bitmap to see if it was initially allowed-for, by the server, and by the valid code-stream (the one with access to the server key for signing/encrypting the bitmap)... That's a fair set of "checks and balances" against site-hacking.
That is all nice, but slow down a bit, keep in mind that XWiki is not an online banking platform or the like, signing and encrypting everything would be an overkill here. There are several different (and more basic) security problems around (XSS, CSRF, privilege escalation, ...), they can't be fixed all at once. Alex
Niels http://nielsmayer.com _______________________________________________ devs mailing list devs@xwiki.org http://lists.xwiki.org/mailman/listinfo/devs
On 03/16/2010 09:33 AM, Caleb James DeLisle wrote:
I don't want this proposal to die because of unnecessary noise which I introduced, I have thought about it and I am in agreement with the general idea of sending the user a hash which must be returned with the post in order for the data to be saved.
I don't like adding code to xwiki-core so I suggest this be made into a component. We would need 2 functions: String getToken() boolean isTokenValid(String token)
getToken uses org.xwiki.bridge.DocumentAccessBridge.getCurrentUser() to get the user who called it and the user name is stored in a HashMap of <String, String> with a random string of text.
If getToken finds a token already in the map, it returns that token (so it may be called multiple times in the generation of a page)
isTokenValid checks the current user against the token then removes the entry from the HashMap so the token may not be reused.
Did I understand the idea correctly that isTokenValid should be called from all macros that modify data, but not from the old core directly? So for example the SaveAction (which saves edited documents at the moment) would not be protected for now, but the future action component would also use isTokenValid at some point?
If a configuration parameter is specified to disable the component, getToken returns "" and isTokenValid returns true.
WDYT?
Caleb
Caleb James DeLisle wrote:
Sergiu Dumitriu wrote:
On 03/10/2010 07:44 PM, Caleb James DeLisle wrote:
Take a look at the "sammy is my hero" worm, myspace sent a hash to the user like the one you propose, the worm made the required get request to get the hash, then made the post along with the hash. What prevents javascript from opening the page with the hash in an iframe and then reading in the iframe to get the hash, then creating a form with the required data and posting it to the save action?
If we were to combine a requirement for post requests with checking of the referrer header, then we would block links, forms and javascript based attacks leaving only an attack through older versions of flash which support referrer forgery and at this point the difficulty of the attack becomes such that we need to consider a wider array of attack vectors. Sammy also required that XSS is enabled.
Protecting from attacks originating in the wiki is kind of impossible at the moment, since JS can be inserted anywhere, and there's no (nice) way to prevent attacks from JS inside the application. As long as JS can be inserted, an attacker can do all the steps that the client would do to perform an action.
The secret token works as a prevention mechanism when the attack comes from another site because the browser security model prevents the attack code to read the form.
I just did a few tests on iframes and I was wrong, they do have good same origin policy.
Caleb
Caleb
Alex Busenius wrote:
Unfortunately, using POST requests instead of GET requests is not enough. It will not prevent attacks that use forms and/or JavaScript to generate POST requests.
Alex
On 03/09/2010 02:48 PM, Caleb James DeLisle wrote:
I had thought about proposing this myself but decided against it because it seems to me like a workaround for problems which can be solved in other ways.
Suppose we were to add a check to the actions which alter data which made sure the request method was 'post' and made it configurable in one of the configuration files? We would have to look over the default skins for incorrect links and leave the configuration option off by default for backward compatibility at least until the next major version but we could provide wiki operators the ability to prevent CSRF.
Caleb
_______________________________________________ devs mailing list devs@xwiki.org http://lists.xwiki.org/mailman/listinfo/devs
_______________________________________________ devs mailing list devs@xwiki.org http://lists.xwiki.org/mailman/listinfo/devs
_______________________________________________ devs mailing list devs@xwiki.org http://lists.xwiki.org/mailman/listinfo/devs
_______________________________________________ devs mailing list devs@xwiki.org http://lists.xwiki.org/mailman/listinfo/devs
Alex Busenius wrote:
On 03/16/2010 09:33 AM, Caleb James DeLisle wrote:
I don't want this proposal to die because of unnecessary noise which I introduced, I have thought about it and I am in agreement with the general idea of sending the user a hash which must be returned with the post in order for the data to be saved.
I don't like adding code to xwiki-core so I suggest this be made into a component. We would need 2 functions: String getToken() boolean isTokenValid(String token)
getToken uses org.xwiki.bridge.DocumentAccessBridge.getCurrentUser() to get the user who called it and the user name is stored in a HashMap of <String, String> with a random string of text.
If getToken finds a token already in the map, it returns that token (so it may be called multiple times in the generation of a page)
isTokenValid checks the current user against the token then removes the entry from the HashMap so the token may not be reused.
Did I understand the idea correctly that isTokenValid should be called from all macros that modify data, but not from the old core directly? No the old core would call it but it wouldn't itself be in the old core. The call goes something like
TokenGenerator tg = Utils.getComponent(TokenGenerator.class); if (tg.isTokenValid(request.getParameter("securitytoken"))) { //do save action... } This makes the old core dependent on the token generator so we have to take care that the token generator does not become dependent on the old core because cyclic dependency is forbidden by maven. Suppose the authentication code were to fire login and logout events with the ObservationManager, this way a user could have a token for the duration of a login (I don't like it but invalidating one save window with another is unacceptable IMO.) WDYT? Caleb
So for example the SaveAction (which saves edited documents at the moment) would not be protected for now, but the future action component would also use isTokenValid at some point?
If a configuration parameter is specified to disable the component, getToken returns "" and isTokenValid returns true.
WDYT?
Caleb
Caleb James DeLisle wrote:
Sergiu Dumitriu wrote:
On 03/10/2010 07:44 PM, Caleb James DeLisle wrote:
Take a look at the "sammy is my hero" worm, myspace sent a hash to the user like the one you propose, the worm made the required get request to get the hash, then made the post along with the hash. What prevents javascript from opening the page with the hash in an iframe and then reading in the iframe to get the hash, then creating a form with the required data and posting it to the save action?
If we were to combine a requirement for post requests with checking of the referrer header, then we would block links, forms and javascript based attacks leaving only an attack through older versions of flash which support referrer forgery and at this point the difficulty of the attack becomes such that we need to consider a wider array of attack vectors. Sammy also required that XSS is enabled.
Protecting from attacks originating in the wiki is kind of impossible at the moment, since JS can be inserted anywhere, and there's no (nice) way to prevent attacks from JS inside the application. As long as JS can be inserted, an attacker can do all the steps that the client would do to perform an action.
The secret token works as a prevention mechanism when the attack comes from another site because the browser security model prevents the attack code to read the form. I just did a few tests on iframes and I was wrong, they do have good same origin policy.
Caleb
Caleb
Alex Busenius wrote:
Unfortunately, using POST requests instead of GET requests is not enough. It will not prevent attacks that use forms and/or JavaScript to generate POST requests.
Alex
On 03/09/2010 02:48 PM, Caleb James DeLisle wrote: > I had thought about proposing this myself but decided against it because it seems > to me like a workaround for problems which can be solved in other ways. > > Suppose we were to add a check to the actions which alter data which made sure the request method > was 'post' and made it configurable in one of the configuration files? We would have > to look over the default skins for incorrect links and leave the configuration > option off by default for backward compatibility at least until the next major version > but we could provide wiki operators the ability to prevent CSRF. > > Caleb > _______________________________________________ devs mailing list devs@xwiki.org http://lists.xwiki.org/mailman/listinfo/devs
_______________________________________________ devs mailing list devs@xwiki.org http://lists.xwiki.org/mailman/listinfo/devs
devs mailing list devs@xwiki.org http://lists.xwiki.org/mailman/listinfo/devs
_______________________________________________ devs mailing list devs@xwiki.org http://lists.xwiki.org/mailman/listinfo/devs
_______________________________________________ devs mailing list devs@xwiki.org http://lists.xwiki.org/mailman/listinfo/devs
On 03/18/2010 05:07 AM, Caleb James DeLisle wrote:
Alex Busenius wrote:
On 03/16/2010 09:33 AM, Caleb James DeLisle wrote:
I don't want this proposal to die because of unnecessary noise which I introduced, I have thought about it and I am in agreement with the general idea of sending the user a hash which must be returned with the post in order for the data to be saved.
I don't like adding code to xwiki-core so I suggest this be made into a component. We would need 2 functions: String getToken() boolean isTokenValid(String token)
getToken uses org.xwiki.bridge.DocumentAccessBridge.getCurrentUser() to get the user who called it and the user name is stored in a HashMap of <String, String> with a random string of text.
If getToken finds a token already in the map, it returns that token (so it may be called multiple times in the generation of a page)
isTokenValid checks the current user against the token then removes the entry from the HashMap so the token may not be reused.
Did I understand the idea correctly that isTokenValid should be called from all macros that modify data, but not from the old core directly? No the old core would call it but it wouldn't itself be in the old core. The call goes something like
TokenGenerator tg = Utils.getComponent(TokenGenerator.class); if (tg.isTokenValid(request.getParameter("securitytoken"))) { //do save action... }
This makes the old core dependent on the token generator so we have to take care that the token generator does not become dependent on the old core because cyclic dependency is forbidden by maven.
Ah, I see. Cyclic dependencies should not be a problem as long as the tokens are cached locally in the token generator and not in the HttpSession.
Suppose the authentication code were to fire login and logout events with the ObservationManager, this way a user could have a token for the duration of a login (I don't like it but invalidating one save window with another is unacceptable IMO.)
This events might still be useful also for the per user+url token cache I wrote about in another mail, to clean up the cache from unfinished requests (user opens edit page and closes the tab). Alex
WDYT?
Caleb
So for example the SaveAction (which saves edited documents at the moment) would not be protected for now, but the future action component would also use isTokenValid at some point?
If a configuration parameter is specified to disable the component, getToken returns "" and isTokenValid returns true.
WDYT?
Caleb
Caleb James DeLisle wrote:
Sergiu Dumitriu wrote:
On 03/10/2010 07:44 PM, Caleb James DeLisle wrote:
Take a look at the "sammy is my hero" worm, myspace sent a hash to the user like the one you propose, the worm made the required get request to get the hash, then made the post along with the hash. What prevents javascript from opening the page with the hash in an iframe and then reading in the iframe to get the hash, then creating a form with the required data and posting it to the save action?
If we were to combine a requirement for post requests with checking of the referrer header, then we would block links, forms and javascript based attacks leaving only an attack through older versions of flash which support referrer forgery and at this point the difficulty of the attack becomes such that we need to consider a wider array of attack vectors. Sammy also required that XSS is enabled.
Protecting from attacks originating in the wiki is kind of impossible at the moment, since JS can be inserted anywhere, and there's no (nice) way to prevent attacks from JS inside the application. As long as JS can be inserted, an attacker can do all the steps that the client would do to perform an action.
The secret token works as a prevention mechanism when the attack comes from another site because the browser security model prevents the attack code to read the form. I just did a few tests on iframes and I was wrong, they do have good same origin policy.
Caleb
Caleb
Alex Busenius wrote: > Unfortunately, using POST requests instead of GET requests is not > enough. It will not prevent attacks that use forms and/or JavaScript to > generate POST requests. > > Alex > > > On 03/09/2010 02:48 PM, Caleb James DeLisle wrote: >> I had thought about proposing this myself but decided against it because it seems >> to me like a workaround for problems which can be solved in other ways. >> >> Suppose we were to add a check to the actions which alter data which made sure the request method >> was 'post' and made it configurable in one of the configuration files? We would have >> to look over the default skins for incorrect links and leave the configuration >> option off by default for backward compatibility at least until the next major version >> but we could provide wiki operators the ability to prevent CSRF. >> >> Caleb >> > _______________________________________________ > devs mailing list > devs@xwiki.org > http://lists.xwiki.org/mailman/listinfo/devs > _______________________________________________ devs mailing list devs@xwiki.org http://lists.xwiki.org/mailman/listinfo/devs
devs mailing list devs@xwiki.org http://lists.xwiki.org/mailman/listinfo/devs
_______________________________________________ devs mailing list devs@xwiki.org http://lists.xwiki.org/mailman/listinfo/devs
_______________________________________________ devs mailing list devs@xwiki.org http://lists.xwiki.org/mailman/listinfo/devs
_______________________________________________ devs mailing list devs@xwiki.org http://lists.xwiki.org/mailman/listinfo/devs
On Mon, Mar 8, 2010 at 6:06 PM, Sergiu Dumitriu <sergiu@xwiki.com> wrote:
First, as Alex said, cookies are not an option since CrossSite requests are valid, normal requests, and they will use the correct cookies.
Exactly. Which is why a cookie containing key-lengths and expiration times that would make it impossible to inject bad data, via replay, man-in-the-middle or other attacks used to subvert submitted form data, and thereby potentially breach security, rights, authentication, or access control. Of course, I'm assuming SSL/TLS to begin with, so that man-in-the-middle, replay and other such attacks can't be done. Without that, even with digest-auth, it's just security through obscurity, providing extra hoops to jump through and extra layers to break, without actually securing anything. In other words, digest-auth doesn't help. SSL/TLS does. Essentially what we're looking for is a solution that prevents a replay attack with form data. How are you going to do a replay attack and generate a one-time (or short lived) cookie whose key-length would take the age-of-the-universe to brute-force decrypt deterministically (and you'd have to recompute this age-of-universe-length brute-force decrypt every few seconds). Furthermore, what if the cookie contained some out of band data, such as nonces to digitally sign (in javascript) the returning form data to prevent the cryptocookie from being captured and replayed along with bogus form data? Alex mentions "make users authenticate themselves each time theywant to edit a page, which is quite inconvenient for a Wiki." -- this is certainly not what I'm talking about. There's no reason to re-auth for each edit, perhaps re-cookie, but not re-auth. Cookies by definition work cross-site, otherwise how would you implement cookie-nets? Of course browsers can be set to prevent this; those with super-strict cookie blocking might need to make an exception, which they'd need to do anyways for many sites given the pervasive use of cookies integrated with multisite access. If you've been using Java for the last decade, chances are you've been using some of the ones I architected or setup alongside SSL.
Second, I already analyzed the possibility of using digest authentication instead of basic (for WebDAV for example), and that's not possible with XWiki, since it requires access to the plain text password. With the current way that passwords are stored (as any object property), it would be too unsafe to do that.
http://en.wikipedia.org/wiki/Digest_access_authentication#Disadvantages has some interesting insights on why you made the right choice in not doing digest-auth in Xwiki: Disadvantages
Digest access authentication is intended as a security trade-off; it is intended to replace unencrypted HTTP Basic access authentication which is extremely weak. However it is not intended to replace strong authentication protocols, such as Public key or Kerberos authentication.
In terms of security, there are several drawbacks with Digest access authentication:
Many of the security options in RFC2617 are optional. If quality-of-protection (qop) is not specified by the server, the client will operate in a security-reduced legacy RFC2069 mode.
Digest access authentication is vulnerable to Man-in-the-middle attack; for
example, a MitM attacker could tell clients to use Basic access authentication or legacy RFC2069 Digest access authentication mode. To extend this further, Digest access authentication provides no mechanism for clients to verify the server's identity.
Some servers require passwords to be stored using reversible encryption.
However, it is possible to instead store the digested value of the username, realm, and password.[1]
Alternative authentication protocols
Some strong authentication protocols for web based applications include:
Public key authentication (usually implemented with HTTPS / SSL client certificates).
Kerberos or SPNEGO authentication, primarily employed by Microsoft
IIS running configured for "Integrated Windows Authentication".
Secure Remote Password protocol (preferably within the HTTPS / TLS layer).
Weak cleartext protocols are also often in use:
Basic access authentication scheme
HTTP+HTML Form based authentication
These weak cleartext protocols used together with HTTPS network encryption resolve many of the threats that Digest access authentication is designed to prevent.
Which brings us back to traditional form-auth solutions using SSL and crypto-cookies: http://en.wikipedia.org/wiki/HTTP%2BHTML_Form_based_authentication -- note that digest auth isn't even worth the trouble
Many of the security options in RFC2617 are optional. If quality-of-protection (qop) is not specified by the server, the client will operate in a security-reduced legacy RFC2069 mode.
Digest access authentication is vulnerable to Man-in-the-middle attack; for
example, a MitM attacker could tell clients to use Basic access authentication or legacy RFC2069 Digest access authentication mode. To extend this further, Digest access authentication provides no mechanism for clients to verify the server's identity.
Security with holes like that isn't really security -- it's just obscurity. -- Niels, http://nielsmayer.com
Hello everyone, I have reimplemented secret token protection as a component, see: https://svn.xwiki.org/svnroot/xwiki/contrib/sandbox/xwiki-csrftoken It uses a page from the "core-functionality" application I proposed lately: https://svn.xwiki.org/svnroot/xwiki/contrib/sandbox/xwiki-application-core-f... This component has 3 methods: Return the current token String getToken() Check if the given token is valid boolean isTokenValid(String token) Return the URL of a resubmission page (see explanation later) String getResubmissionURL() These methods are accessible from scripts using ScriptService, e.g. from velocity: $!{services.csrf.getToken()} $services.csrf.isTokenValid("$!{request.getParameter('form_token')}") $!{services.csrf.getResubmissionURL()} The tokens are stored in an internal map, one token per user. A current limitation is that the tokens never expire (unless the component is reinitialized). This is not nice, but can easily be changed later, once login/logout events and a scheduling component are available. The resubmission page is shown in case the token verification fails. It shows a message to the user, explaining what happened and asks for confirmation. If the user clicks "Yes", the blocked request continues with a correct token, if the user clicks "No", the page returns back to the originating page. The idea behind resubmission is to prevent users from loosing data in case of bugs, server restarts or similar issues, but still stop CSRF attacks. A limitation is that Ajax requests without correct token will still just fail until the user reloads the page. CSRF checks can be disabled by setting core.csrftoken.enabled = false in xwiki.properties, this is the default for now. The component as is does nothing even when enabled, the actual checks will need to be done in all cases where some data is changed, i.e. in actions, some templates, REST component etc. All forms, links and Ajax requests used to modify data will need to include a parameter called "form_token" with the value of the current token. If the data is changed in velocity (some templates do this), then a CSRF check must be added there. I have added an updated patch for most important applications, all templates and actions to the JIRA issue: http://jira.xwiki.org/jira/browse/XWIKI-4873 Not yet protected is the REST API and some applications: officeimporter, ircbot, photoalbum, invitation, annotations, search. The protection seems to work, but I really need more people to try it out on a larger wiki. A big TODO are the selenium tests (especially selenium 1). They often use a direct URL to delete/create/edit a page, such requests fail when CSRF checks are enabled. I would really like to see CSRF protection included into XWiki (disabled by default) even though many tests fail with enabled CSRF checks (25 ui-tests, 18 selenium-tests). This is already a very big patch, and fixing all tests first will make it even bigger and harder to apply. WDYT? Alex On 03/07/2010 08:46 PM, Alex Busenius wrote:
Hi,
I would like to add support for secret token verification to prevent CSRF attacks (see http://jira.xwiki.org/jira/browse/XWIKI-4873).
The main idea is to add a random token as a parameter to each request that requires edit/comment/admin rights and check that this token is present on the server side. Since there are many ways one can modify documents, it would require many changes all over the place, in particular:
* add a public method to XWikiContext: String getSecretToken() that generates a random token and caches it in the session * add a public method to XWikiRightService*: boolean isRequestLegitimate(String action, XWikiContext context) to check if the given action is allowed to be executed * add the following API methods to Context: String getSecretToken() boolean checkSecretToken() for including the secret token into forms/AJAX requests and checking that the current request is legitimate * add a new configuration parameter core.useSecretTokenValidation for disabling this functionality, and the corresponding method useSecretTokenValidation() to CoreConfiguration and DefaultCoreConfiguration * use the secret token (hidden input for forms or parameter of GET requests) in all templates (*.vm files in web/standard and skins, velocity macros in applications/**/resources/*.xml) * check the secret token in Save/Delete/Upload/etc.-Actions and throw an exception to deny the access if the check fails * check the secret token in all templates that directly modify data (e.g. web/standard/src/main/webapp/templates/admin.vm) * fix all selenium tests that directly modify pages using the open(...) method * make sure nothing else is broken
WDYT?
Thanks, Alex _______________________________________________ devs mailing list devs@xwiki.org http://lists.xwiki.org/mailman/listinfo/devs
participants (6)
-
Alex Busenius -
Alex Busenius -
Caleb James DeLisle -
Marius Dumitru Florea -
Niels Mayer -
Sergiu Dumitriu