Search code examples
cookiesckeditorcsrf-protection

How does CKEditor protects against CSRF?


When using the CKEditor (4.9.1), you may notice that a ckCsrfToken cookie is being set. From the release notes, this seems to be used as a CSRF protection when uploading files.

I couldn't find any documentation on how the CKEditor protects against CSRF attacks. Is CKEditor implementing the Double Submit Cookie strategy?

The reason I'm asking is that our client wants an explanation on the purpose of this cookie, which is not HTTP only.

Any link to a reference documentation or source code would be appreciated :)


Solution

  • TL;DR: evidences show that CKEditor allows any third party File Uploader to protect itself against CSRF attacks by using the Double Submit Cookie strategy.

    Now for the full story: looking at the source code, it appears that the CKEditor generates a CSRF token on demand and stores it in a cookie (which cannot be HTTP only as it's set on client side):

    /**
     * Returns the CSRF token value. The value is a hash stored in `document.cookie`
     * under the `ckCsrfToken` key. The CSRF token can be used to secure the communication
     * between the web browser and the server, i.e. for the file upload feature in the editor.
     *
     * @since 4.5.6
     * @returns {String}
     */
    getCsrfToken: function() {
        var token = CKEDITOR.tools.getCookie( TOKEN_COOKIE_NAME );
    
        if ( !token || token.length != TOKEN_LENGTH ) {
            token = generateToken( TOKEN_LENGTH );
            CKEDITOR.tools.setCookie( TOKEN_COOKIE_NAME, token );
        }
    
        return token;
    }
    

    Then both the File Tools and the File Browser plugins submit that token when calling the upload URL, as seen in the fileUploadRequest handler:

    // Append token preventing CSRF attacks.
    $formData.append( 'ckCsrfToken', CKEDITOR.tools.getCsrfToken() );
    

    and in the appendToken method:

    tokenElement.setAttribute( 'value', CKEDITOR.tools.getCsrfToken() );
    

    The CKEditor control itself does not ship with a "file uploader". It is therefore the responsibility of the developer integrating the CKEditor in his/her product to use this token to implement CSRF protection.

    CKFinder --the paid "file uploader" that integrates with CKEditor-- makes use of the CSRF token and, looking at the release notes, it seems that this token was added for the CKFinder:

    Note for CKEditor users: In order to upload files directly inside CKEditor with updated CKFinder (with CSRF protection enabled), CKEditor should also be updated to the latest stable version (CKEditor 4.5.6 released on 9th Dec, 2016).

    Finally, the source code of CKFinder makes it clear that the CSRF protection is implemented using the Double Submit Cookie strategy (see DoubleSubmitCookieTokenValidator.php):

    /**
     * DoubleSubmitCookieTokenValidator constructor.
     *
     * @param string $tokenParamName
     * @param string $tokenCookieName
     * @param int    $minTokenLength
     */
    public function __construct($tokenParamName = 'ckCsrfToken', $tokenCookieName = 'ckCsrfToken', $minTokenLength = 32)
    {
        $this->tokenParamName = $tokenParamName;
        $this->tokenCookieName = $tokenCookieName;
        $this->minTokenLength = $minTokenLength;
    }
    
    /**
     * Checks if the request contains a valid CSRF token.
     *
     * @param Request $request
     *
     * @return bool `true` if the token is valid, `false` otherwise.
     */
    public function validate(Request $request)
    {
        $paramToken = trim((string) $request->get($this->tokenParamName));
        $cookieToken = trim((string) $request->cookies->get($this->tokenCookieName));
    
        if (strlen($paramToken) >= $this->minTokenLength && strlen($cookieToken) >= $this->minTokenLength) {
            return $paramToken === $cookieToken;
        }
    
        return false;
    }