programing

코드 점화기 세션이 Ajax 호출로 버그가 발생함

telecom 2023. 7. 24. 22:16
반응형

코드 점화기 세션이 Ajax 호출로 버그가 발생함

내 CodeIgniter 앱은 세션 라이브러리를 사용하고 데이터를 DB에 저장합니다.

특정 아약스 호출 후 빈 세션이 생성되는 문제가 발생했습니다.

조사해보니, 세션 검증이 필요한 두 개의 동시 함수 호출이 있었던 것 같습니다.하나는 실패하고 다른 하나는 괜찮을 것입니다.

동시에 발사하지 않음으로써 이 문제를 해결할 수 있었습니다.하지만 저는 여전히 왜 실패하는지 이해할 수 없습니다.한 통화가 사용자 쿠키를 업데이트하고 두 번째 통화가 무효화하는 것과 관련이 있습니까?아니면 DB를 읽을 때 어떻게든 죽을까요?

세션 코어 클래스를 조금 살펴보았지만 원인에 대한 단서를 찾지 못했습니다.

만약 누군가가 이전에 같은 문제를 가지고 있었다면 디버깅 방법이나 원인이 무엇인지에 대한 조언을 해주시면 감사하겠습니다.

감사합니다!

편집:

저는 원래 408 상태 리턴이 있다고 말했습니다.그것은 관련이 없는 사건이었습니다.

MyVar.refresh()를 병렬로 실행하는 기능은 다음과 같습니다.

function (event)
{
    var self$ = this.a$;
    var uid  = this.b$.val();
    var tid  = this.c$.val();
    var jqxhr = $.post('/controller1/index',{'uid':uid,'tid':tid,'action':true},function(re)
    {
        if(re.message != 'success')
        {
            MyVar.alert('<span class="msg_error sprite"></span>' + re.error);
            MyVar.refresh();
        } 

    },'json');
    MyVar.refresh();
    return stopDefault(event);
};

가능한 솔루션:

다음을 찾았습니다: http://codeigniter.com/forums/viewthread/102456/

분명히 그것은 아약스와 잘 어울리지 않습니다.한 가지 해결책은 Ajax 호출일 경우 세션 업데이트를 허용하지 않는 것입니다. 유일한 문제는 우리 사이트가 대부분 Ajax로 구축되어 있다는 것입니다.

또한 sess_time_to_update를 매우 빈번한 것으로 낮추었고 Ajax는 잘 지내고 있었습니다.또한 브라우저를 새로 고쳤으며 시간이 초과되지 않았습니다.Ajax 호출 시 세션 ID가 이미 변경되었고 브라우저 쿠키가 업데이트되지 않은 이유를 알 수 없습니다.

사용해 보세요.

<?php
/**
 * ------------------------------------------------------------------------
 * CI Session Class Extension for AJAX calls.
 * ------------------------------------------------------------------------
 *
 * ====- Save as application/libraries/MY_Session.php -====
 */

class MY_Session extends CI_Session {

    // --------------------------------------------------------------------

    /**
     * sess_update()
     *
     * Do not update an existing session on ajax or xajax calls
     *
     * @access    public
     * @return    void
     */
    public function sess_update()
    {
        $CI = get_instance();

        if ( ! $CI->input->is_ajax_request())
        {
            parent::sess_update();
        }
    }

}

// ------------------------------------------------------------------------
/* End of file MY_Session.php */
/* Location: ./application/libraries/MY_Session.php */

이 문제는 세션 클래스의 sess_update 함수에서 X초 후에 새 session_id를 생성합니다.모든 페이지에는 session_id가 있으며, Ajax 호출 전에 session_id가 만료되면 해당 호출이 실패합니다.

이름이 MY_Session(또는 설정한 접두사)인 /application/libraries/에 php 파일을 만들고 이 코드를 붙여넣으면 그게 전부입니다.이 함수는 세션 클래스의 sess_update 함수를 재정의하여 모든 요청이 Ajax에 의해 수행되었는지 확인하고 sess_update 함수를 건너뜁니다.

sess_expiration을 더 높은 값으로 설정하는 것은 좋지 않습니다.이 기능은 세션 히잡으로부터 사용자를 보호하는 보안 기능입니다.

PD: 저는 영어를 잘 하지 못합니다. 이해가 안 되면 말씀해 주세요.

안정적인 분기에 병합될 때까지 솔루션(최종적으로!)은 데이터베이스 스키마와 결합된 Areson의 commit 245bef5를 사용하는 것입니다.

CREATE TABLE IF NOT EXISTS  `ci_sessions` (
    session_id varchar(40) DEFAULT '0' NOT NULL,
    ip_address varchar(45) DEFAULT '0' NOT NULL,
    user_agent varchar(120) NOT NULL,
    last_activity int(10) unsigned DEFAULT 0 NOT NULL,
    user_data text NOT NULL,
    prevent_update int(10) DEFAULT NULL,
    PRIMARY KEY (session_id),
    KEY `last_activity_idx` (`last_activity`)
);

자세한 내용은 1283개의 댓글을 위에서 아래로 당기십시오.

이 문제는 config.php의 sess_time_to_update 매개 변수 때문에 발생했습니다.CI를 사용하여 세션 ID를 새 ID로 업데이트합니다.Ajax 호출에서 변경 사항이 발생하면 CI는 브라우저에 새 세션 ID를 알리기 위해 새 쿠키를 보냅니다.안타깝게도 브라우저는 이 쿠키를 무시하고 이전 세션 ID를 유지하는 것 같습니다.

구성에서 sess_time_to_update를 sess_expiration으로 설정하여 수정했습니다.

$config['sess_time_to_update'] = $config['sess_expiration']; 

다음 구성을 사용할 때 코드 점화기 버전 2.1.3에서도 이 문제가 발생했습니다.

$config['sess_use_database']    = TRUE;

$config['sess_time_to_update']  = 300;

나는 그것이 아약스 요청과 관련이 없고 오히려 코드 점화기의 버그와 관련이 있다고 생각합니다.

세션을 데이터베이스에 저장하면 300초 후에 로그아웃이 강제로 실행되는 것 같습니다.3시간 동안 검색하고 분석한 결과, 코드에서 명확한 버그와 불분명한 버그를 발견했고, 다음과 같이 버그를 해결했습니다.

새 파일 MY_Session을 만듭니다.php가 응용 프로그램/디버깅 폴더에 있습니다.

다음 코드를 추가합니다.

<?php
// fixed by sirderno 2013

if ( ! defined('BASEPATH')) exit('No direct script access allowed'); 

class MY_Session extends CI_Session
{

    public function __construct()
    {
        parent::__construct();
    }

    /**
     * Update an existing session
     *
     * @access  public
     * @return  void
     */
    public function sess_update()
    {
        // We only update the session every five minutes by default
        if (($this->userdata['last_activity'] + $this->sess_time_to_update) >= $this->now)
        {
            return;
        }

        // Save the old session id so we know which record to
        // update in the database if we need it
        $old_sessid = $this->userdata['session_id'];
        $new_sessid = '';
        while (strlen($new_sessid) < 32)
        {
            $new_sessid .= mt_rand(0, mt_getrandmax());
        }

        // To make the session ID even more secure we'll combine it with the user's IP
        $new_sessid .= $this->CI->input->ip_address();

        // Turn it into a hash
        $new_sessid = md5(uniqid($new_sessid, TRUE));

        // Update the session data in the session data array
        $this->userdata['session_id'] = $new_sessid;
        $this->userdata['last_activity'] = $this->now;

        // _set_cookie() will handle this for us if we aren't using database sessions
        // by pushing all userdata to the cookie.
        $cookie_data = NULL;

        // Update the session ID and last_activity field in the DB if needed
        if ($this->sess_use_database === TRUE)
        {
            // set cookie explicitly to only have our session data
            $cookie_data = array();
            foreach (array('session_id','ip_address','user_agent','last_activity') as $val)
            {
                $cookie_data[$val] = $this->userdata[$val];
            }

            $cookie_data['session_id'] = $new_sessid;  // added to solve bug

                    //added to solve bug
            if (!empty($this->userdata['user_data']))
                $cookie_data['user_data'] = $this->userdata['user_data'];

            $this->CI->db->query($this->CI->db->update_string($this->sess_table_name, array('last_activity' => $this->now, 'session_id' => $new_sessid), array('session_id' => $old_sessid)));

        }

        // Write the cookie
        $this->_set_cookie($cookie_data);
    }

    /**
     * Write the session cookie
     *
     * @access  public
     * @return  void
     */
    public function _set_cookie($cookie_data = NULL)
    {
        if (is_null($cookie_data))
        {
            $cookie_data = $this->userdata;
        }

        // Serialize the userdata for the cookie
        $cookie_data = $this->_serialize($cookie_data);

        if ($this->sess_encrypt_cookie == TRUE)
        {
            $cookie_data = $this->CI->encrypt->encode($cookie_data);
        }
        else
        {
            // if encryption is not used, we provide an md5 hash to prevent userside tampering
            $cookie_data = $cookie_data.md5($cookie_data.$this->encryption_key);
        }

        $_COOKIE[ $this->sess_cookie_name ] = $cookie_data;  // added to solve bug

        $expire = ($this->sess_expire_on_close === TRUE) ? 0 : $this->sess_expiration + time();

        // Set the cookie
        setcookie(
                    $this->sess_cookie_name,
                    $cookie_data,
                    $expire,
                    $this->cookie_path,
                    $this->cookie_domain,
                    $this->cookie_secure
                );
    }   
}


?>

분명한 버그는 업데이트된 쿠키에 'user_data'를 저장하지 않았다는 것입니다.명확하지 않은 버그는 Session 파일에서 sess_read() 함수를 실행한다는 것입니다.php는 새로운 세션 ID를 업데이트한 후에 왜 이런 일이 일어나는지 모르겠습니다. 왜냐하면 저는 그것이 Session.php의 생성자에 쓰여진 것처럼 업데이트 전이 아니라 업데이트 전에 실행될 것이라고 예상했기 때문입니다.sess_read() 함수는 오래된 쿠키 정보를 오래된 세션 ID로 읽기 시작하고 데이터베이스의 세션 ID와 비교하려고 하지만 session_id 업데이트 후에는 더 이상 데이터베이스에 존재하지 않으므로 로그아웃이 발생합니다.

Session.php 파일의 functionsess_read에 있는 이 코드 행은 오래된 쿠키 정보를 읽습니다.

$session = $this->CI->input->cookie($this->sess_cookie_name);

그래서 MY_Session의 _set_cookie 함수에서.php i는 서버의 오래된 쿠키 정보를 새로운 것으로 업데이트하기 위해 이 코드 라인을 추가했습니다.

$_COOKIE[ $this->sess_cookie_name ] = $cookie_data;  // added to solve bug

이 수정 프로그램을 사용하면 'ss_time_to_update'와 'ss_use_database'를 함께 사용하면 됩니다.이것은 간단하고 간단한 버그 수정입니다.

나는 아약스로 이미지를 업로드할 때 정확히 같은 문제를 겪었고, 나는 그것을 설정했습니다.sess_expiration구성 시:

$config['sess_expiration'] = time()+10000000;

그리고 그것이 제 문제를 해결했습니다.

좋은 해결책이 여기 있습니다. sess_time_to_update 등으로 무엇이든 하십시오. 아래 해결책을 시도해 보십시오.

  1. https://degreesofzero.com/article/fixing-the-expiring-session-problem-in-codeigniter.html
  2. http://ellislab.com/forums/viewthread/138823/ #725078

솔루션 번호 "1"에 대해 스크립트를 조금 더 업데이트합니다. CI와 많이 충돌한 후 CI 세션이 손실되는 두 가지 이유가 있습니다. 하나는 잘못된 Ajax 호출이 세션을 업데이트하고 세션이 손실되는 경우입니다. 두 번째는 잘못된 Ajax 호출이 CI의 SESSION 라이브러리에서 sess_destroy 함수에 영향을 미치는 경우입니다. 그래서 조금 만들었습니다."1." 솔루션의 변경

/*add this code to MY_Session.php*/     
function sess_destroy()
{
// Do NOT update an existing session on AJAX calls.
if (!$this->CI->input->is_ajax_request())
{
return parent::sess_destroy();
}
/* WHEN USER HIS/HER SELF DO A LOGOUT AND ALSO IF PROGRAMMER SET TO LOGOUT USING AJAX CALLS*/
$firsturlseg = $this->CI->security->xss_clean( $this->CI->uri->segment(1) );        
$securlseg = $this->CI->security->xss_clean( $this->CI->uri->segment(2) );      
if((string)$firsturlseg==(string)'put ur controller name which u are using for login' &&    (string)$securlseg==(string)'put url controler function for logout')
{
 return parent::sess_destroy();
}
}

이것들이 사람들에게도 도움이 되기를 바랍니다.

코어 CI 세션 클래스 처리 세션에 결함이 있는 것 같습니다.

매력적으로 작동하는 대체 세션 라이브러리를 찾았습니다.

CI 대체 세션 라이브러리

코어 CI_Session 클래스를 교체하는 것보다 확장하는 것이 좋습니다.

확장하려면 파일을 만듭니다.MY_Session.phpapplication/libraries대체 라이브러리의 내용을 붙여넣고 바꾸기class CI_Session로.class MY_Session extends CI_Session.

보호된 항목 제거_flashdata_mark(),_flashdata_sweep(),_get_time(),_set_cookie(),_serialize(),_unserialize(),_sess_gc()기능들.

도움이 되길 바랍니다.

아직도 오래된 CI 버전이 많이 사용되고 있는 것 같습니다. 이 스레드가 오래되었음에도 불구하고 2센트를 추가하고 싶었습니다.저는 코드 이그니터에서 AJAX 호출 문제를 해결하는 데 며칠을 보냈으며, 주요 문제를 다루는 솔루션이 있지만 일부 솔루션은 '훌륭하지' 않습니다.제가 (아직) 사용하고 있는 CI 버전은2.1.3

내 애플리케이션에서는 유효한 세션을 유지하기 위해 AJAX 호출이 last_activity 필드를 업데이트해야 하므로 AJAX 호출에 대한 세션 업데이트를 포기하는 것만으로는 충분하지 않습니다.

이 CI 버전에서는 sess_update 및 sess_read에 대한 오류 검사가 부적절합니다(최근 버전은 조사하지 않았습니다). 많은 문제가 여기서 시작됩니다.

1부:sess_update()

여러 AJAX 호출은 경합 조건을 생성하여 이후 호출에 대해 데이터베이스를 잠급니다.업데이트 쿼리를 실행하려고 하지만 데이터베이스가 잠겨 있으면 오류가 발생하고 쿼리가 false를 반환하지만 쿠키가 여전히 새 데이터로 업데이트되어 있습니까?... BAD!또한 모든 Ajax 호출에 대해 새로운 session_id가 필요하지 않습니다.우리는 last_activity만 업데이트하면 됩니다.사용해 보십시오.

    function sess_update()
{
    // We only update the session every five minutes by default
    if (($this->userdata['last_activity'] + $this->sess_time_to_update) >= $this->now)
    {
        return;
    }

    // Save the old session id so we know which record to
    // update in the database if we need it

    $old_sessid = $this->userdata['session_id'];
    //Assume this is an AJAX call... keep the same session_id
    $new_sessid = $old_sessid;

    if( !$this->CI->input->is_ajax_request() ){ 
        //Then create a new session id
        while (strlen($new_sessid) < 32)
        {
            $new_sessid .= mt_rand(0, mt_getrandmax());
        }

        // To make the session ID even more secure we'll combine it with the user's IP
        $new_sessid .= $this->CI->input->ip_address();

        // Turn it into a hash
        $new_sessid = md5(uniqid($new_sessid, TRUE));

    }

    // _set_cookie() will handle this for us if we aren't using database sessions
    // by pushing all userdata to the cookie.
    $cookie_data = NULL;

    // Update the session ID and last_activity field in the DB if needed
    if ($this->sess_use_database === TRUE)
    {

        //TRY THE QUERY FIRST!
        //Multiple simultaneous AJAX calls will not be able to update because the Database will be locked. ( Race Conditions )
        //Besides... We don't want to update the cookie if the database didn't update
        $query = $this->CI->db->query($this->CI->db->update_string($this->sess_table_name, array('last_activity' => $this->now, 'session_id' => $new_sessid), array('session_id' => $old_sessid)));
        if( $query ){

            // Update the session data in the session data array
            $this->userdata['session_id'] = $new_sessid;
            $this->userdata['last_activity'] = $this->now;

            // set cookie explicitly to only have our session data
            $cookie_data = array();
            foreach (array('session_id','ip_address','user_agent','last_activity') as $val)
            {
                $cookie_data[$val] = $this->userdata[$val];
            }

            // Write the cookie
            $this->_set_cookie($cookie_data);

        }else{
            //do nothing... we don't care, we still have an active retreivable session and the update didn't work
            //debug: error_log( "ERROR::" . $this->CI->db->_error_message() ); //Shows locked session database
        }
    }else{
        // Update the session data in the session data array
        $this->userdata['session_id'] = $new_sessid;
        $this->userdata['last_activity'] = $this->now;

        // Write the cookie
        $this->_set_cookie($cookie_data);
    }
}

2: 파트 2:sess_read()

여기서 아주 비슷한 문제가...쿼리 중에 데이터베이스가 잠기는 경우가 있습니다.이번에는 오류를 무시할 수 없다는 것만 빼면요.세션이 있는지 확인하기 위해 세션을 읽는 중입니다.따라서 데이터베이스 오류가 잠길 경우 오류를 확인하고 다시 시도할 수 있습니다(필요한 경우 몇 번).테스트에서는 에서 2번 이상 시도하지 않았습니다.또한 당신에 대해서는 잘 모르겠지만, 저는 php가 잘못된 쿼리 결과를 확인하지 않음으로써 치명적인 오류로 실패하는 것을 원하지 않습니다.이 코드를 직접 시도하려면 session.php 파일의 맨 위에 이 정보가 있어야 합니다.

var $sess_query_attempts = 5;

참로고전, 은가아다닙니체이것▁entire다아'의 전체가 아닙니다.sess_read를 수행

$query = $this->CI->db->get($this->sess_table_name);

//Multiple AJAX calls checking
//But adding add a loop to check a couple more times has stopped premature session breaking
$counter = 0;
while( !$query && $counter < $this->sess_query_attempts     ){

    usleep(100000);//wait a tenth of a second

   $this->CI->db->where('session_id', $session['session_id']);

    if ($this->sess_match_ip == TRUE)
   {
        $this->CI->db->where('ip_address', $session['ip_address']);
    }

    if ($this->sess_match_useragent == TRUE)
    {
        $this->CI->db->where('user_agent', $session['user_agent']);
    }

    $query = $this->CI->db->get($this->sess_table_name);

    $counter++;
}
if ( !$query || $query->num_rows() == 0)
{
    $this->CI->db->where('session_id', $session['session_id']);
    $query = $this->CI->db->get( $this->sess_table_name );

    $this->sess_destroy();
    return FALSE;
}

어쨌든, 나는 이 문제에 대한 완전한 답이 없고 나처럼 AJAX를 많이 사용하는 사이트에서 아직도 초기 세션 타임아웃을 경험하고 있을 수 있는 사람들과 내 연구 결과를 공유해야 한다고 느꼈습니다.

글을 쓰다session_start()

언급URL : https://stackoverflow.com/questions/7980193/codeigniter-session-bugging-out-with-ajax-calls

반응형