diff --git a/App/Controllers/Posts.php b/App/Controllers/Posts.php index 70c946b..92f8c96 100644 --- a/App/Controllers/Posts.php +++ b/App/Controllers/Posts.php @@ -7,6 +7,7 @@ use App\Models\Access; use \Core\Token; use \Core\Session; use \Core\Redirect; +use \Core\XSS; class Posts { @@ -81,11 +82,13 @@ class Posts $url = 'Data/pengumuman.html'; + $status = ''; $privilage = ''; if (Session::exists('userid')) { $post = $this->model->showAll(); $privilage = Session::get('privilage'); + $status = 'loggedin'; } if ($post !== false) { @@ -102,6 +105,7 @@ class Posts } View::render($url, [ 'posts' => $posts, + 'status' => $status, 'privilage' => $privilage ]); } @@ -159,7 +163,8 @@ class Posts $creator = $post['creator']; $editor = $post['editor']; - $post['content'] = htmlspecialchars_decode($post['content']); + // Decode XSS data + $post = XSS::decode($post); $table = 'users'; @@ -241,11 +246,8 @@ class Posts } } - if (isset($args['content'])) { - $args['content'] = htmlspecialchars($args['content']); - } elseif (isset($args['category'])) { - $args['category'] = htmlspecialchars($args['category']); - } + // Avoid XSS attack + $args = XSS::avoid($args); if (isset($table)) { if ($this->model->entry($args, $table)) { @@ -272,7 +274,9 @@ class Posts Redirect::to('/posts/category'); die(); } - $args['content'] = htmlspecialchars($args['content']); + + // Avoid XSS attack + $args = XSS::avoid($args); $id = $args['id']; unset($args['id']); diff --git a/Core/XSS.php b/Core/XSS.php new file mode 100644 index 0000000..1ff0b62 --- /dev/null +++ b/Core/XSS.php @@ -0,0 +1,62 @@ + $value) { + $args[$key] = htmlspecialchars($value); + } + + // Re-include excluded data + if (isset($includes)) { + foreach ($includes as $key => $value) { + $args[$key] = $value; + } + } + + return $args; + } + } + + public static function decode($args = []) { + if ($args) { + if (array_key_exists('exclude', $args)) { + $excludes = $args['exclude']; + + foreach ($excludes as $exclude) { + $includes[$exclude] = $args[$exclude]; + unset($args[$exclude]); + } + + unset($args['exclude']); + } + + foreach ($args as $key => $value) { + $args[$key] = htmlspecialchars_decode($value); + } + + // Re-include excluded data + if (isset($includes)) { + foreach ($includes as $key => $value) { + $args[$key] = $value; + } + } + + return $args; + } + } +} diff --git a/_tests/unit/XSSTest.php b/_tests/unit/XSSTest.php new file mode 100644 index 0000000..1e4896c --- /dev/null +++ b/_tests/unit/XSSTest.php @@ -0,0 +1,56 @@ + 'Abcdefghijklmnopqrstuvwxyz', + 'data_xss' => 'Az', + 'data_xss_exclude' => 'Az', + 'data_xss_exclude_2' => 'Az', + 'data_xss_exclude_3' => 'Az', + ]; + + $args['exclude'] = [ + 'data_xss_exclude', + 'data_xss_exclude_3' + ]; + + $expected = [ + 'data_biasa' => 'Abcdefghijklmnopqrstuvwxyz', + 'data_xss' => '<b>A</b><b>z</b>', + 'data_xss_exclude' => 'Az', + 'data_xss_exclude_2' => '<i>A</i><i>z</i>', + 'data_xss_exclude_3' => 'Az' + ]; + + $this->assertEquals($expected, XSS::avoid($args)); + } + + /** + * + * @test + */ + public function DecodeDataXSSBerhasil() { + $args = [ + 'data_encode' => '<b>A</b><b>z</b>', + 'data_encode_exclude' => '<b>A</b><b>z</b>' + ]; + + $args['exclude'] = [ + 'data_encode_exclude' + ]; + + $expected = [ + 'data_encode' => 'Az', + 'data_encode_exclude' => '<b>A</b><b>z</b>' + ]; + + $this->assertEquals($expected, XSS::decode($args)); + } +}