Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

The request has been black-holed - CakePHP

Tags:

php

cakephp

I'm using CakePHP's SecurityComponent. And it's very essential as it saves forms from CSRF attacks. My project has total 10-12 forms and this is my first CakePHP project. After enabling SecurityComponent I was in a bit trouble but could get rid off after some careful minutes. This is the last form of my project and seems everything is correct to me but still the form is being black holed :(. Can anybody please tell me the problem? I don't want to disable CSRF checking or SecurityComponent. Here is my view code:

<?php
echo $this->Form->create('Record');
?>
<script type="text/javascript"> var me = new MetroExam(); </script>
<div class="exam_paper">
    <div class="question_box" id="q_b">
        <div class="q_n_a_header">
            <div class="instructions">
                <b>Instructions:</b><br>
                <?=$inst['value_text']; ?>
            </div>
            <div id="timer">Please wait</div>
        </div>
        <div id="q_paper">
           <img id="q" style="display: none;" src="/oes/<?=$exam['path'].'?ts='.time(); ?>">

            <img id="loading_img" src="/oes/img/loading.gif">
        </div>
    </div>
    <div class="ans_box" id="a_b">
        <!-- information about answer paper. !important -->
        <?php
        $i = 0;

        //these fields are essential for evaluating ans paper
        echo $this->Form->hidden('submit', array('value' => 'true'));
        echo $this->Form->hidden('start_time', array('value' => ''));
        echo $this->Form->hidden('end_time', array('value' => ''));
        echo $this->Form->hidden('duration', array('value' => ''));
        echo $this->Form->hidden('valid', array('value' => ''));
        echo $this->Form->hidden('passed', array('value' => ''));

        //options for all radio
        $options     = array(
            '1' => 'A',
            '2' => 'B',
            '3' => 'C',
            '4' => 'D'
        );
        if($exam['choices'] == 5){
            $options['5'] = 'None';
        }

        $questions = (int)$exam['questions']; // 40 <= $exam['questions'] <= 100
        $i = 1;
        while($questions--){
            echo '<div class="'.(($i%2)==1?'each_answer_even':'each_answer_odd').'" id="ans-'.$i.'">';
            echo '<div class="q_number">'.($i <= 9 ? '0'.$i : $i).'</div>';
            $name       = 'ans'.str_pad($i, 3, '0', STR_PAD_LEFT);
            $attributes = array('empty' => false, 'legend' => false, 'onclick' => 'me.answer_click('.$i.')');
            echo '<div class="mcq">'.$this->Form->radio($name, $options, $attributes).'</div>';
            echo '</div>';
            $i++;
        }
        echo $this->Form->end('Submit');
        ?>
    </div>
</div>

This is basically a MCQ exam form. Where each group has 4 or 5 radio buttons and total 40 to 100 groups in a form. I'm using CakePHP 2.4. Thanks in advance.

like image 679
A. K. M. Tariqul Islam Avatar asked Nov 15 '13 13:11

A. K. M. Tariqul Islam


2 Answers

As per the comments, the problem appears because you are changing the hidden values of the form. The way SecurityComponent works, is that it "locks" the name of the fields, so an evildoer can't add new fields or change the values once the form is sent. But it is even more strict with the hidden values, because it locks the field name and value. So by changing it with jQuery you're blackhole-ing your own form.

There's a nice little post where I learned this, take a look at it. The author there also explains two ways of bypassing this problem. One is to disable the security for hidden fields, so the hash calculated for the token doesn't include those values... which isn't really secure...
And another solution is to modify the FormHelper, and tell it to "lock" the hidden fields names but not the values. I don't remember what version of Cake the author uses for the example, but the code given there should be practicaly the same. So with that solution, you can tell the form to not be so strict with you with an option array.

Oh, and the other option given there (this is what I normally use) (I just read it now there... I thought I figure that on my own... oh well), is to just use normal input text fields for the ones you want hidden, and add a css style like display:none.

It's up to you what you think is best. I like the css option because is simpler, and really, if someone is going to mess with my css evily (with firebug or something like that), they might just as well do it with the values of hidden fields, it doesn't require any more effort. You should take all the extra steps and verifications when handling that form submission anyway. But like I said, up to you which do you think is best for your situation.

like image 143
Nunser Avatar answered Oct 22 '22 01:10

Nunser


In addition to what was already posted, here's something else what might be causing the problem: in my case, a hidden input had it's name overwritten.

$this->Form->create('ExampleModel'):
$this->Form->input('foo_bar', array(
    'type' => 'hidden',
    'name' => 'foo_bar',
));

As a result, the final $this->request->data had the corresponding key $this->request->data['foo_bar']. It was not within the $this->request->data['ExampleModel'] array, and that's what the problem was.

To fix the issue, I had to remove the name key from the template, making the input belong to the model's data, and then just change the controller to accept that value.

Hope this helps someone else.

Update: this would also work on a form not attached to any model, e.g.:

$this->Form->create(false, array(
    'url' => '/example',
)):
like image 23
mehov Avatar answered Oct 22 '22 00:10

mehov