Membuat aplikasi dengan Node Js menjadi lebih aman

Perkembangan teknologi sudah bukan menjadi hal yang awam bagi sebagian banyak orang. Bahkan teknologi menjadi makanan sehari-hari, bagi mereka yang memang sangat membutuhkannya, baik itu untuk kegiatan belajar, bekerja, berbelanja dan kegiatan lainnya. Namun apakah kamu tahu bahwa dibalik apa yang sedang kamu nikmati saat ini, ada sebuah nilai yang teramat amat sangat penting dan membutuhkan effort yang cukup besar untuk memertahankannya, yah, salah satunya adalah security.

Dibalik keamanan disana banyak para CEO, Engineer dan Konsumen yang ketakutan, mungkin mereka takut suatu saat aplikasi yang telah mereka kerjakan dengan susah payah tiba-tiba data database mereka hilang ? atau mungkin saja suatu saat konsumen sedang asyiknya berbelanja tiba-tiba kartu kredit yang mereka gunakan habis tanpa ada sisa ? Tetapi pada dasarnya semua itu dapat diminimalisir dengan adanya kehati-hatian dalam menggunakan teknologi. Teknologi bagi para programmer dan penggiat dunia IT sudah tidak asing lagi dengan adanya perkembangan bahasa pemrograman, banyak mereka mencoba untuk mengupgrade skill dan melakukan uji coba terkait dengan bahasa pemrograman yang ada untuk mengembangkan aplikasi mereka.

Pada artikel ini saya akan mencoba untuk sharing bagaimana mengamankan aplikasi Node JS yang sedang kita buat, mengapa harus Node JS ? Apabila kita melihat trend teknologi yang digunakan pada akhir-akhir ini node JS merupakan aplikasi yang memiliki kelebihan dalam hal performance dibandingkan dengan bahasa pemrograman lainnya.


Membangun aplikasi dibaratkan dengan membangun sebuah rumah. Bagi sebagian banyak orang pasti sangat mengidamkan untuk membangun rumah yang aman dan nyaman. Dalam membangun rumah anda harus memiliki pondasi yang kuat sebelum menambahkan semua fitur yang ada. Rumah pada dasarnya juga harus memiliki kunci agar tindakan yang tidak diinginkan seperti pencurian tidak terjadi. Seperti halnya membangun sebuah aplikasi, pada dasarnya untuk mengembangkan aplikasi/sistem juga memerlukan sebuah kunci khusus untuk mengamankan dan mencegah pencurian data bahkan manipulasi data.

Mungkin anda pernah mendengar bagaimana awal mulai sebuah toko online tiba-tiba rugi hanya karena aplikasi mereka tidak aman, bahkan banyak data pelanggan tercuri termasuk kartu kredit. Kesalahan itu dapat diminimalisir dengan cara membangun sistem yang kuat, menutup celah sebaik mungkin agar penyerang tidak dapat masuk melalui sistem yang anda buat. Artikel ini akan membahas bagaimana dasar mengamankan sebuah aplikasi yang dibuat menggunakan Node JS. Perlu anda ketahui bahwa platform Node.js dibangun oleh Engine Javascript dari Google yang bernama V8, salah satu keuntungannya adalah Node JS selalu mengikuti perkembangan standar ECMAScript, jadi browser anda akan selalu mendukung fitur-fitur di Node.js. Berikut merupakan dasar keamanan yang dapat diterapkan dalam membangun aplikasi menggunakan Node JS :

1. Selalu gunakan ‘use strict’ pada awal program atau function

Sumber : blog.guinatal.com

Use strict mulai ada dan diperkenalkan pada JavaScript 1.8.5 (ECMAScript versi 5). Tujuan penggunaan use strict adalah untuk memperketat penulisan kode pemrograman pada bahasa pemrograman javascript. Salah satu aturan yang terikat didalamnnya adalah bahwa semua penggunaan variable yang belum dideklare tidak dapat digunakan atau akan mengakibatkan error. Hal ini memungkinkan bahwa semua penulisan program yang dibuat menjadi lebih aman. Mode strict akan memberlakukan kesalahan-kesalahan kecil yang dilakukan pada saat menulis program menjadi pesan error pada saat program dijalankan, sehingga dengan cepat developer akan segera memperbaiki program dan akan melatif programmer menjadi lebih disiplin. Penggunaan use strict sangat mudah, cukup menuliskan baris ‘use strict’ pada awal baris program atau pada awal function. Beberapa hal yang dilarang dalam menulis program pada mode Strict diantaranya yaitu :

a. Membuat variable baru tanpa melakukan declare terlebih dahulu pada nama variable yang akan dibuat. Karena pada mode normal, variabel yang dibuat tanpa di declare akan tetap berjalan.

'use strict'
bola = 0; //Dikenali sebagai kesalahan (error)

b. Menggunakan delete statement yang digunakan pada variabel, fungsi ataupun argument.

'use strict'
var phi = 3.14;
delete phi; //Dikenali sebagai kesalahan (error)

c. Membuat duplicate property. Dengan kata lain semua properti yang dibuat dalam suatu object pada mode strict harus unik.

'use strict';
var indonesia = { kabupaten: 1, kota: 2, kota: 3, provinsi: 4 }; // Dikenali sebagai kesalahan (error)

d. Mendefinisikan attribute pada object secara berulang pada variabel yang sama. Aturan mode strict melarang sebuah object yang telah didefinisikan dalam sebuah attribute atau property untuk didefinisikan kembali.

//Membuat object dengan property readonly
var facebook = {};
Object.defineProperty(facebook, 'app', { value: 50, writable: false });
facebook.app = 103; //Dikenali sebagai kesalahan (error)
// Membuat object dengan property readonly
var twitter = { get app() { return 51; } };
twitter.app = 130; //Dikenali sebagai kesalahan (error)
// Membuat object dengan property pada object yang tidak dikenali
var google = {};
Object.preventExtensions(google);
google.newProp = 'app'; // Dikenali sebagai kesalahan (error)

e. Mode strict mensyaratkan untuk membuat parameter pada fungsi secara unik.

'use strict'
function sum(data1, data1, data2) { // Dikenali sebagai kesalahan (error)
}

f. Mode strict melarang sintax oktal. Aturan baru pada ECMAScript 2015 penggunaan oktal dapat digunakan dengan prefix number yang digunakan sebagai awalan yaitu “0o”.

let Obj1 = 060; // Dikenali sebagai kesalahan (error)
let Obj2 = \060; // Dikenali sebagai kesalahan (error)
let Obj3 = 060 + 180 + 200; // Dikenali sebagai kesalahan (error)

g. Mode strict di ECMAScript 2015 melarang pengaturan properti pada nilai-nilai primitif.

function() {
'use strict';
false.true = ''; // Dikenali sebagai kesalahan (error)
(14).sailing = 'home'; // Dikenali sebagai kesalahan (error)
//Penggunaan with statement tidak diperbolehkan
'with'.you = 'so cool'; // Dikenali sebagai kesalahan (error)
})();

2. Gunakan TLS dan SSL untuk mengamankan Transmisi Data

sumber : avidhawk.com

Apakah anda tahu bahwa semua data yang dikirim melalui jaringan internet tanpa adanya enkripsi dapat mudah dibaca orang lain ? pastinya anda tidak ingin ketika anda melakukan transaksi secara online atau menggunakan kartu kredit, seseorang dengan leluasanya mengamati aktivitas anda. Secure Socket Layar (SSL) memungkinkan untuk melakukan enkripsi secara acak setiap data yang akan dikirim. Dengan standar Transport Layer Security (TLS), data yang akan dikirim dimodifikasi menggunakan algoritma kriptografi supaya tidak dapat terbaca oleh pihak yang tidak diinginkan. Hal ini akan menjamin kerahasiaan informasi yang dikirim oleh pengguna internet.

Untuk menjalankan sebuah server dengan HTTPS pada Node JS, kita hanya memerlukan sertifikat SSL yang valid dan terpercaya seperti halnya Symantec, Thawte, GeoTrust, RapidSSL, dan Comodo. Berikut merupakan cara sederhana bagaimana server https dapat berjalan pada Node.js. Contoh Implementasi HTTPS pada Node JS :

3. Melakukan konfigurasi keamanan pada HTTP Header

Sumber : www.cloudnueva.com

HTTP merupakan bagian dari protocol yang digunakan untuk berkomunikasi. Hal yang perlu digaris bawahi bahwa, selama kita berselancar didunia komunikasi yang serba terbuka ini, tidak menjamin bahwa aktivitas yang kita lakukan itu aman. Seperti halnya, dengan aplikasi yang akan kita share secara publik, dimana setiap orang dapat mengaksesnya, tidak dapat dihindari juga bawah attacker dalam konteks ini bertindak sebagai Man In the Middle (MITM), juga dengan leluasa dapat mengakses sistem yang telah kita buat, bahkan secara terang-terangan melakukan serangan melalui pintu ini. Beberapa serangan yang dapat dilakukan pada celah ini diantaranya yaitu dalam bentuk DNS Spoofing, XSS (Cross-Site Scripting), Clickjacking (Penyisipan konten ilegal), pembajakan HTTPS dan kegiatan mencari informasi penting terkait dengan kekuatan sistem baik itu dari sisi hardware maupun software (Information Gathering).

Tahap pengamanan pada HTTP Header ini pada dasarnya dapat dilakukan pada 2 sisi yaitu server (Contoh: Apache, Nginx dll) dan juga dari sisi Aplikasi (Node JS). Pada sisi aplikasi yang dibuat dengan menggunakan Node.js, metode atau cara mengamankannnya dapat dilakukan dengan cara menerapkan module baru yaitu helmet. Module ini dilengkapi dengan beberapa variasi konfigurasi yang dapat diterapkan pada HTTP header. Module yang berjalan diatas framework Express ini juga dapat digunakan dengan sangat mudah, berikut merupakan tahap instalasi module helmet pada Node Js:

a. Install module helmet pada aplikasi node JS

npm install helmet –save

b. Menggunakan modul helmet pada baris program

var express = require('express')
var helmet = require('helmet')
var app = express()
app.use(helmet())

4. SQL Injection

Sumber : media.licdn.com

Yaps, SQL Injection ini akan melakukan bypass terhadap penggunaan query yang tidak terfilter dengan baik. Hal ini memungkinkan user dapat memanipulasi masukan string dan menjalankan inputan bersama query yang ternanam pada program di lapisan basis data. Pada celah ini juga, bahkan user dapat menggunakan query DROP untuk menghapus database yang ada. Pada umumnya serangan pada jenis ini dibagi menjadi 2 jenis yaitu standar SQL injection dan blind SQL injection. Pada standar SQL Injection penyerang akan mendapatkan pesan error secara langsung pada halaman web dan dengan mudah menerapkan injeksi query secara mudah. Berbeda dengan halnya Blind SQL injection, penyerang akan menginjeksi sistem secara bertahap melalui celah SQL yang sudah diketahui, hingga mencari query yang cocok untuk mendapatkan data yang diinginkan. Basic penyerangan menggunakan metode ini, dapat dilihat pada implementasi dibawah ini :

a. Contoh script yang rentan terhadap serangan SQL Injection

b. Dump database menggunakan sample data dibawah ini

c. Ketika anda menjalankan program diatas http://localhost:3000/1 , secara normal halaman web akan menampilkan data pada id 1 :

[{"id":1,"full_name":"Sam Ben","user_name":"samben","email":"samben@gmail.com"}]

d. Filter data yang tidak divalidasi memungkinkan user untuk menginjeksi command SQL secara langsung dengan mengakses :

http://localhost:3000/%22;SELECT%20*%20FROM%20users%20WHERE%20%221%22=%221

e. Sistem akan melakukan query secara berulang dengan manipulasi yang diterima melalui user , hingga sistem akan mengeksekusi query dibawah ini :

SELECT * FROM users WHERE name="";SELECT * FROM users WHERE "1"="1";

f. Dampaknya sistem akan menampilkan semua data yang ada pada tabel users.

[[],[{"id":1,"full_name":"Sam Ben","user_name":"samben","email":"samben@gmail.com"},{"id":2,"full_name":"Ofani Dariyan","user_name":"ofani","email":"ofanidariyan@hotmail.com"},{"id":3,"full_name":"Toni Stark","user_name":"toni","email":"tonistark@hotmail.com"},{"id":4,"full_name":"Mrs Valak","user_name":"valak","email":"valak@conjuring.com"},{"id":5,"full_name":"Iron Wine","user_name":"iron","email":"iron@wine.com"}]]

g. Hal ini juga memungkinkan untuk melakukan drop tabel users menggunakan command line dibawah ini:

http://localhost:3000/";DROP%20TABLE%20users;

Problem SQL injection dapat dengan mudah diatasi pada semua bahasa pemrograman yang ada, mulai dari PHP, ASP, Node JS dll. Anda dapat memanfaatkan connection.escape() untuk memfilter/memvalidasi data yang masuk melalui user. Validasi ini juga setara dengan antisipasi yang dilakukan pada pemrograman PHP yaitu mysqli_escape_string(). Jadi, dengan memodifikasi baris program pada parameter query menjadi connection.escape(req.param(‘id’)) ini akan memvalidasi setiap masukan yang dikirim user menjadi spesial karakter dan data yang diterima oleh user akan terdeksi sebagai string (bukan bagian dari command). Akan tetapi model validasi tersebut (connection.escape()) tidak sepenuhnya benar dan tidak tepat untuk diterapkan pada aplikasi yang dibuat dengan menggunakan Node JS, karena skema diatas pada kenyataannya akan memisahkan perintah program dan query yang dikirimkan oleh user dan hasil eksekusi pada endpoint akan berdampak tidak adanya data yang dapat ditampilkan. Opsi berikut ini merupakan teknik pengamanan yang tepat dan efektif yang dapat dilakukan pada aplikasi Node JS:

//Query SQL yang sudah terfilter dengan benar
connection.query('SELECT * FROM users WHERE id= ?', [req.param('id')], function(err, rows, fields) {
if (err) {
next(err);
return;
}
res.send(JSON.stringify(rows));
});

5. OS Command Injection

Terkadang sebuah aplikasi web juga memerlukan komunikasi dengan sistem operasi, yang memungkinkan aplikasi yang tengah kita buat juga dapat menjalankan dasar perintah OS seperti halnya shell. Hal ini tentunya akan memudahkan kita dalam menjalankan semua perintah pada OS, aplikasi juga dapat dengan mudah mengakses data, bahkan mengeksekusi file yang ada dalam komputer. Akan tetapi tahukah anda, bahwa hal ini sangatlah berbahaya jika tidak dapat digunakan secara tepat, dan akan menyebabkan masalah baru pada sistem keamanan suatu aplikasi. Berikut merupakan contoh penerapan fungsi child_process.exec() pada Node JS yang memungkinkan aplikasi menampilkan data pada suatu path/folder.

a.Contoh dasar shell command execution pada node JS untuk menampilkan data pada path tertentu.

b. Bagaimana jika user diberikan hak akses melalui input untuk melakukan eksekusi secara langsung ?

c. Hasil eksekusi pada user input http://localhost:3000/listfile

total 18 drwxr-xr-x 1 Ofani 197609 0 Apr 4 00:11 . drwxr-xr-x 1 Ofani 197609 0 Apr 3 21:43 .. -rw-r--r-- 1 Ofani 197609 952 Apr 4 00:09 app.js -rw-r--r-- 1 Ofani 197609 624 Apr 4 00:17 child.js drwxr-xr-x 1 Ofani 197609 0 Apr 3 22:01 node_modules -rw-r--r-- 1 Ofani 197609 364 Apr 3 22:01 package.json

d. User dengan leluasa melakukan eksekusi untuk pindah dan masuk kedalam folder yang diinginkan. http://localhost:3000/listfile/%20halo%20-la

total 4 drwxr-xr-x 1 Ofani 197609 0 Apr 4 00:29 . drwxr-xr-x 1 Ofani 197609 0 Apr 4 01:15 .. -rw-r--r-- 1 Ofani 197609 952 Apr 4 00:09 app.js

e. Untuk membatasi akses user pada sub-command anda dapat menerapkan fungsi child_process.execFile(), dimana fungsi ini berjalan dengan cara mengambil perintah yang diterima melalui user sebagai array dan tidak dijalankan pada lingkup shell, hal ini dapat dikatakan bahwa fungsi tersebut tidak rentan terhadap perintah injeksi.

Bagaimana menarik bukan ? :D 
Semoga bermanfaat untuk teman-teman semua, Salam Belajar :)