DokuWiki

It's better when it's simple

User Tools

Site Tools


devel:security

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revisionPrevious revision
Next revision
Previous revision
devel:security [2009-06-25 08:53] – old revision restored 195.35.72.54devel:security [2023-08-14 13:41] (current) Klap-in
Line 1: Line 1:
 ====== Security Guidelines for Plugin Authors ====== ====== Security Guidelines for Plugin Authors ======
  
-Creating [[:plugins]] for DokuWiki is very easy even for novice PHP programmers. To make sure your plugin does not compromise the security of the whole wiki it is installed on, you should follow the guidelines outlined on this page.+Creating [[:plugins]] for DokuWiki is very easy even for novice PHP [[devel:plugins|programmers]]. To make sure your plugin does not compromise the security of the whole wiki it is installed on, you should follow the guidelines outlined on this page.
  
-FIXME this page is in a very raw state and should be extended with more indepth info, links and examples.+:!: Improvement of this page is always welcome. It'in a very raw state and should be extended with more indepth info, links and examples
 + 
 +===Summary=== 
 + 
 +A list of the most common security issues and how to avoid them can be found on this page. A short summary: 
 +  * Cross Site Scripting (XSS) -- inserts malicious code into website to manipulate site in browser of user 
 +  * Cross Site Request Forgery (CSRF) -- tricks to let you do unknowingly harmful actions on your site  
 +  * Remote Code Inclusion -- includes code on server that's executed there 
 +  * Information leaks -- there is too much information shown 
 +  * SQL injection -- one can do unwanted requests on your data 
 + 
 +Also there is added a note about [[#reporting Security Issues]].
  
-A list of the most common security issues and how to avoid them can be found below. 
  
 ===== Cross Site Scripting (XSS) ===== ===== Cross Site Scripting (XSS) =====
Line 15: Line 25:
 DokuWiki's plugin mechanism gives plugin developers a great deal of flexibility. In the case of syntax plugins in particular, the framework gives plugins the ability to work with raw unprocessed output. This means the wiki page data which reaches your plugin has not been processed at all. And there will be no further processing on the output after it leaves your plugin. DokuWiki's plugin mechanism gives plugin developers a great deal of flexibility. In the case of syntax plugins in particular, the framework gives plugins the ability to work with raw unprocessed output. This means the wiki page data which reaches your plugin has not been processed at all. And there will be no further processing on the output after it leaves your plugin.
  
-At an absolute minimum the plugin should ensure any raw data output has all HTML special characters converted to HTML entities using the [[phpfn>htmlspecialchars]] function. DokuWiki provides a convenient shortcut called [[xref>hsc()]] for the function. URLs values should be escaped using [[phpfn>rawurlencode]].+===Escaping output=== 
 +At an absolute minimum the plugin should ensure any raw data output has all HTML special characters converted to HTML entities using the [[phpfn>htmlspecialchars()]] function. DokuWiki provides a convenient shortcut called [[xref>hsc()]] for the function. URLs values should be escaped using [[phpfn>rawurlencode()]].
  
 Also any wiki data extracted and used internally (eg. user names) should be treated with suspicion. Also any wiki data extracted and used internally (eg. user names) should be treated with suspicion.
 +
 +===Input checking===
 +Check always all your input. Use whitelists, filters, conversions to the exact data type you mean e.g. from a number inputted as mixed php value to integer and more to ensure you have __only__ data you allowed.
 +
 +Please also refer to our chapter on processing [[request vars]] like ''_GET'', ''_POST'' or ''_SERVER''.
  
  
-**See also:**+==See also:==
  
   * [[wp>Cross-site scripting]]   * [[wp>Cross-site scripting]]
Line 39: Line 55:
     // common plugin functions ommited     // common plugin functions ommited
  
-    function connectTo($mode) { +    public function connectTo($mode) { 
-        $this->Lexer->addSpecialPattern('!!!.*?!!!',$mode,'plugin_bold');+        $this->Lexer->addSpecialPattern('!!!.*?!!!', $mode, 'plugin_bold');
     }     }
  
-    function handle($match, $state, $pos, &$handler){ +    public function handle($match, $state, $pos, Doku_Handler $handler){ 
-        return array(substring($match,3,-3));+        return [substring($match, 3, -3)];
     }     }
  
-    function render($mode&$R, $data) { +    public function render($formatDoku_Renderer $renderer, $data) { 
-        if($mode != 'xhtml') return false; +        if($format != 'xhtml') return false; 
-        $R->doc .= '<b>'.$data[0].'</b>';+        $renderer->doc .= '<b>' . $data[0] . '</b>';  // no escaping
     }     }
 } }
Line 62: Line 78:
     // common plugin functions ommited     // common plugin functions ommited
  
-    function connectTo($mode) { +    public function connectTo($mode) { 
-        $this->Lexer->addSpecialPattern('!!!.*?!!!',$mode,'plugin_bold');+        $this->Lexer->addSpecialPattern('!!!.*?!!!', $mode, 'plugin_bold');
     }     }
  
-    function handle($match, $state, $pos, &$handler){ +    public function handle($match, $state, $pos, Doku_Handler $handler){ 
-        return array(substring($match,3,-3));+        return [substring($match, 3, -3)];
     }     }
  
-    function render($mode&$R, $data) { +    public function render($formatDoku_Renderer $renderer, $data) { 
-        if($mode != 'xhtml') return false; +        if($format != 'xhtml') return false; 
-        $R->doc .= '<b>'.htmlspecialchars($data[0]).'</b>';+        $renderer->doc .= '<b>' . htmlspecialchars($data[0]) . '</b>'; //escaping
     }     }
 } }
Line 84: Line 100:
  
 <code php> <code php>
-<form acttion="" method="post"> +<form action="" method="post"> 
-    <input type="text" name="q" value="<?php echo $_REQUEST['q']?>" /> +    <input type="text" name="q" value="<?php echo $_REQUEST['q']?>" />  
-    <input type="submit" />+    <input type="submit" />                     //no escaping
 </form> </form>
 </code> </code>
Line 92: Line 108:
 Providing ''%%"><script>alert('bang')</script>%%'' as user input would exploit the vulnerability. Providing ''%%"><script>alert('bang')</script>%%'' as user input would exploit the vulnerability.
  
-To fix the form use the [[phpfn>htmlspecialchars]] function:+To fix the form use the [[phpfn>htmlspecialchars|htmlspecialchars()]] or DokuWiki shortcut [[xref>hsc|hsc()]] function:
  
 <code php> <code php>
-<form acttion="" method="post"> +<form action="" method="post"> 
-    <input type="text" name="q" value="<?php echo htmlspecialchars($_REQUEST['q'])?>" /> +    <input type="text" name="q" value="<?php echo hsc($_REQUEST['q'])?>" /> 
-    <input type="submit" />+    <input type="submit" />                                      //escaping
 </form> </form>
 </code> </code>
 +
 +In general it is recommended to not hand-craft forms, but use DokuWiki's [[form|form library]].
  
 === Classes and other Attributes === === Classes and other Attributes ===
Line 111: Line 129:
 </code> </code>
  
-In the render method there might be code like this:+In the render method of this syntax there might be code like this:
  
 <code php> <code php>
-$renderer->doc .= '<div class="msg_'.$class.'">'.htmlspecialchars($message).'</div>';+$renderer->doc .= '<div class="msg_' . $class . '">'  //$class can be everything 
 +                       . htmlspecialchars($message) 
 +                . '</div>'; 
 +                                 
 </code> </code>
  
-As you can see the message itself is properly escaped, but the class is not. Instead of escaping it might be more sensible to use a whitelist of allowed classes instead:+As you can see the message itself is properly escaped, but the class is not. Instead of escaping it might be more sensible to use a whitelist of allowed classes instead with a default fallback:
  
 <code php> <code php>
-$allowed = array('notice','info','warning','error')+$allowed = ['notice', 'info', 'warning', 'error']  // whitelist 
-if(!in_array($class,$allowed){ +if(!in_array($class, $allowed){                          
-    $class = 'notice'; //unknown input, fall back to a sane default+    $class = 'notice'; // unknown input, fall back to a sane default
 } }
-$renderer->doc .= '<div class="msg_'.$class.'">'.htmlspecialchars($message).'</div>';+$renderer->doc .= '<div class="msg_' . $class . '">' 
 +                       . htmlspecialchars($message) 
 +                . '</div>';
 </code> </code>
  
-=== URLs ===+===input URLs ===
  
 When a plugin accepts URLs as input you need to make sure, users can not pass the ''%%javascript://%%'' pseudo protocol. When a plugin accepts URLs as input you need to make sure, users can not pass the ''%%javascript://%%'' pseudo protocol.
Line 134: Line 157:
  
 <code php> <code php>
-if(!preg_match('/^https?:\/\//i',$url)) $url = ''; // empty URL on protocol mismatch+// empty URL on protocol mismatch 
 +if(!preg_match('/^https?:\/\//i', $url)) 
 +    $url = ''; 
 +}
 </code> </code>
 +
 +===== Cross Site Request Forgery (CSRF) =====
 +
 +This vulnerability often appears into plugins due to the lack of understanding of this issue, often confused with the XSS.
 +
 +Cross Site Request Forgery refers to an attack where the victim's browser is tricked by a malicious site to ask for a page on a vulnerable site to do an unwanted action. The attack assumes the victim's browser has credentials to change something on the vulnerable site.
 +
 +===Adding security token===
 +
 +DokuWiki offers functions to help you deal against CSRF attacks. [[xref>getSecurityToken()]] will create a token that should be used to protect any authenticated action. It has to be included in links or forms triggering that action. All forms created with the [[form|form library]] will have security tokens added automatically, for handcrafted forms the [[xref>formSecurityToken()]] function can be used.
 +
 +
 +It is your resposibility as the plugin author to actually check the token before executing authorized actions using the [[xref>checkSecurityToken()]] function.
 +
 +==See also==
 +
 +  * [[wp>Cross Site Request Forgery]]
 +  * [[https://www.owasp.org/index.php/Cross-Site_Request_Forgery_%28CSRF%29|OWASP explanation]]
 +
 +==== Typical Vulnerability Example ====
 +
 +Below is the simplest example to start. You may have a more complicated plugin of your own to secure, here is just a simple example based on form.
 +
 +Imagine you want to know something which can be answered to Yes or No, you would have a form of this type:
 +
 +<code html>
 +<form action="" method="GET">
 +    <input type="radio" name="yn" value="Yes" />
 +    <input type="radio" name="yn" value="No" />
 +    <input type="submit" value="Answer" />
 +</form>
 +</code>
 +
 +Then you process this form as follows:
 +
 +<code php>
 +global $INPUT;
 +
 +if($INPUT->get->has('yn')){
 +    do_something_with_yn($INPUT->get->str('yn'));
 +}
 +</code>
 +
 +So a user is connected to answer this question, but he doesn't know the response yet. Let's take time to think and browse the web...
 +Now the user is visiting a malicious website, one which know, or not, that the user may be connected to your DokuWiki. In this website, the developer included this HTML image tag:
 +
 +<code html>
 +<img src="http://your.dokuwi.ki/formpage?yn=Yes" />
 +</code>
 +
 +What will the user's browser do then?
 +
 +The browser will process this image as any other and will send a request to this URL. Your plugin will then see that ''$_GET['yn']'' is set and will call the ''do_something_with_yn()'' function.
 +
 +That's one of the examples of CSRF. Now, how to fix this security hole?
 +
 +==== Prevent CSRF ====
 +
 +Remember your form above? Let's add an input in it:
 +
 +<code html>
 +<form action="" method="GET">
 +    <input type="hidden" name="sectok" value="<?php getSecurityToken(); ?>" />
 +    <input type="radio" name="yn" value="Yes" />
 +    <input type="radio" name="yn" value="No" />
 +    <input type="submit" value="Answer" />
 +</form>
 +</code>
 +
 +Do you see the first input? Yes? Good. Now you have to check the security token when you receive the form, before processing it:
 +
 +<code php>
 +global $INPUT;
 +
 +if($INPUT->get->has('yn') && checkSecurityToken()) {
 +    do_something_with_yn($INPUT->get->str('yn'));
 +}
 +</code>
 +
 +As the malicious website will never find the value of the "sectok" hidden input, your form is no longer vulnerable to CSRF.
 +
 +**Note:** If the security token is not valid, the ''checkSecurityToken()'' function displays a message which informs the user.
 +
 +
  
 ===== Remote Code Inclusion ===== ===== Remote Code Inclusion =====
  
-This attack allows an attacker to inject (PHP) code into your application. This may occur on including files, or using unsafe operations functions like [[phpfn>eval]] or [[phpfn>system]].+This attack allows an attacker to inject (PHP) code into your application. This may occur on including files, or using unsafe operations functions like [[phpfn>eval()]] or [[phpfn>system()]].
  
 **Always filter any input** that will be used to load files or that is passed as an argument to external commands. **Always filter any input** that will be used to load files or that is passed as an argument to external commands.
Line 162: Line 272:
 ===== Reporting Security Issues ===== ===== Reporting Security Issues =====
  
-If you encounter an issue with a plugin please inform the author of the plugin via email.+If you encounter an issue with a plugin please inform the author of the plugin via email, optionally putting [[andi@splitbrain.org|Andi]] or the [[:mailinglist]] on CC.
  
-Additionally a ''securityissue'' field with a short description of the problem should be added to the [[plugins:repository|data]] on the page of the plugin. This will create a red warning box and will delist the plugin from the main plugin list.+Additionally a ''securityissue'' field with a short description of the problem should be added to the [[plugin:repository|data]] on the page of the plugin. This will create a red warning box and will delist the plugin from the main plugin list.
  
 Once the issue was fixed and a new release was made, this field should be removed again. Once the issue was fixed and a new release was made, this field should be removed again.
- 
devel/security.1245912814.txt.gz · Last modified: 2009-06-25 08:53 by 195.35.72.54

Except where otherwise noted, content on this wiki is licensed under the following license: CC Attribution-Share Alike 4.0 International
CC Attribution-Share Alike 4.0 International Donate Powered by PHP Valid HTML5 Valid CSS Driven by DokuWiki