You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
256 lines
6.4 KiB
Markdown
256 lines
6.4 KiB
Markdown
|
5 years ago
|
# Security and API
|
||
|
|
|
||
|
|
* Defense on depth
|
||
|
|
* Best Practices for web servers
|
||
|
|
+ switch off unnecessary funtionality
|
||
|
|
+ limit secure remote access
|
||
|
|
+ use accounts with limited privileges
|
||
|
|
+ segregate development, testing and live environment
|
||
|
|
+ segregate data
|
||
|
|
+ secrity patches
|
||
|
|
+ monitor and audit servers and logs
|
||
|
|
+ use security tools
|
||
|
|
* Top 10 Application security risks
|
||
|
|
+ Injection -
|
||
|
|
+ Broken authentication - compromised passwords
|
||
|
|
+ sensitive data exposure
|
||
|
|
+ xxe
|
||
|
|
+ broken acess control
|
||
|
|
+ security misconfiguration
|
||
|
|
|
||
|
|
[Equifax case study](https://www.csoonline.com/article/3444488/equifax-data-breach-faq-what-happened-who-was-affected-what-was-the-impact.html)
|
||
|
|
* security patches
|
||
|
|
* broken authentication
|
||
|
|
* broken access control
|
||
|
|
* security misconfiguration
|
||
|
|
* single point of failure
|
||
|
|
* lack of management commitment
|
||
|
|
|
||
|
|
## Security od Data in motion
|
||
|
|
* HTTPS / FTPS
|
||
|
|
* Type of SSL Certificates
|
||
|
|
+ Signed by a Cerficate Authority (CA)
|
||
|
|
+ Self-signed certificates (less trusted. For testing)
|
||
|
|
|
||
|
|
+ self sigend
|
||
|
|
```
|
||
|
|
$ openssl genrsa -out key.pem
|
||
|
|
$ openssl req -new -key key.pem -out csr.pem
|
||
|
|
$ openssl x509 -req -days 9999 -in csr.pem -signkey key.pem -out cert.pem
|
||
|
|
$ rm csr.pem
|
||
|
|
```
|
||
|
|
|
||
|
|
```Javascript
|
||
|
|
|
||
|
|
```
|
||
|
|
* role based access control
|
||
|
|
|
||
|
|
## Security date at rest
|
||
|
|
* encrypt
|
||
|
|
+ sensitive files
|
||
|
|
+ storage drive
|
||
|
|
+ password
|
||
|
|
* security of username and password
|
||
|
|
|
||
|
|
## Regulation and Standards
|
||
|
|
* [international](https://www.pcisecuritystandards.org/)
|
||
|
|
* [Singapore](https://www.mas.gov.sg/regulation/guidelines/technology-risk-management-guidelines)
|
||
|
|
* [Personal Data Protection Act](https://www.pdpc.gov.sg/Overview-of-PDPA/The-Legislation/Personal-Data-Protection-Act)
|
||
|
|
* [FintTech Service](https://singaporefintech.org/sfa-launches-digital-self-assessment-framework-to-fast-track-fintech-firms-partnerships-with-financial-institutions/)
|
||
|
|
|
||
|
|
## API Security
|
||
|
|
* Basic Authentication
|
||
|
|
* API key
|
||
|
|
* Bearer token
|
||
|
|
* JSON Web Token (JWT)
|
||
|
|
|
||
|
|
## SQL Injection attack
|
||
|
|
|
||
|
|
* sending body `{ id = "5 or 1=1" }`, will return all records. Thus, data leak
|
||
|
|
* need strong validation of inputs
|
||
|
|
|
||
|
|
```javascript
|
||
|
|
// GET route for /user/id query
|
||
|
|
// with body = { "id": 2 }
|
||
|
|
app.get("/user/id", (request, response) => {
|
||
|
|
console.log(request.body);
|
||
|
|
// !!! validation example !!!
|
||
|
|
if (request.body.id === null
|
||
|
|
|| Number.isNaN(request.body.id)
|
||
|
|
|| !Number.isInteger(request.body.id)) {
|
||
|
|
response.send("Some id error occur");
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
//
|
||
|
|
connection.query(`SELECT * FROM users WHERE user_id = ${request.body.id}`,
|
||
|
|
(err, result) => {
|
||
|
|
if (err) {
|
||
|
|
response.send("Some id error occur");
|
||
|
|
}
|
||
|
|
else {
|
||
|
|
response.send(result);
|
||
|
|
}
|
||
|
|
});
|
||
|
|
});
|
||
|
|
|
||
|
|
```
|
||
|
|
|
||
|
|
## Code organisation & management
|
||
|
|
* folder tree
|
||
|
|
+ \server.js
|
||
|
|
+ \database.js
|
||
|
|
+ \routes => store all routes
|
||
|
|
+ \routes\customer.js
|
||
|
|
+ \routes\seller.js
|
||
|
|
|
||
|
|
* modularise into individual module file
|
||
|
|
+ server.js : setup server listen and route linkage
|
||
|
|
```javascript
|
||
|
|
const express = require("express");
|
||
|
|
const bodyParser = require("body-parser");
|
||
|
|
|
||
|
|
const CustomerRouter = require("./routes/customer");
|
||
|
|
const SellerRouter = require("./routes/seller");
|
||
|
|
|
||
|
|
let app = express(); //uri mapper
|
||
|
|
app.use(bodyParser.json());
|
||
|
|
|
||
|
|
app.use("/customer", CustomerRouter);
|
||
|
|
app.use("/seller", SellerRouter);
|
||
|
|
|
||
|
|
app.listen(3000);
|
||
|
|
```
|
||
|
|
+ database.js : database connection
|
||
|
|
```javascript
|
||
|
|
const mysql = require("mysql");
|
||
|
|
|
||
|
|
let params = {
|
||
|
|
host: "localhost",
|
||
|
|
user: "root",
|
||
|
|
password: "root",
|
||
|
|
database: "sales",
|
||
|
|
};
|
||
|
|
|
||
|
|
mysqlConnection = mysql.createConnection(params);
|
||
|
|
|
||
|
|
mysqlConnection.connect((err) => {
|
||
|
|
if (err) {
|
||
|
|
console.log("Failed to Connect");
|
||
|
|
} else {
|
||
|
|
console.log("Connection successful");
|
||
|
|
}
|
||
|
|
});
|
||
|
|
|
||
|
|
module.exports = mysqlConnection;
|
||
|
|
```
|
||
|
|
+ customer.js : customer apis
|
||
|
|
```javascript
|
||
|
|
const express = require("express");
|
||
|
|
const connection = require("../database"); // import database connection
|
||
|
|
|
||
|
|
CustomerRouter = express.Router();
|
||
|
|
|
||
|
|
// localhost:3000/customer/
|
||
|
|
CustomerRouter.get("/", (req, res) => {
|
||
|
|
connection.query("select * from customer", (err, rows) => {
|
||
|
|
if (err) {
|
||
|
|
console.log(err);
|
||
|
|
res.send("Some error occurred");
|
||
|
|
} else {
|
||
|
|
res.send(rows);
|
||
|
|
}
|
||
|
|
});
|
||
|
|
});
|
||
|
|
|
||
|
|
// localhost:3000/customer/name/Zixuan
|
||
|
|
CustomerRouter.get("/name/:value", (req, res) => {
|
||
|
|
connection.query(
|
||
|
|
`select * from customer where customer_name = '${req.params.value}'`,
|
||
|
|
(err, rows) => {
|
||
|
|
if (err) {
|
||
|
|
console.log(err);
|
||
|
|
res.send("Some error occurred");
|
||
|
|
} else {
|
||
|
|
res.send(rows);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
);
|
||
|
|
});
|
||
|
|
|
||
|
|
// localhost:3000/customer/id/10
|
||
|
|
CustomerRouter.delete("/id/:value", (req, res) => {
|
||
|
|
connection.query(
|
||
|
|
`delete from customer where customer_id = ${req.params.value}`,
|
||
|
|
(err, rows) => {
|
||
|
|
if (err) {
|
||
|
|
console.log(err);
|
||
|
|
res.send("Some error occurred");
|
||
|
|
} else {
|
||
|
|
res.send("Deleted Successfully");
|
||
|
|
}
|
||
|
|
}
|
||
|
|
);
|
||
|
|
});
|
||
|
|
|
||
|
|
module.exports = CustomerRouter;
|
||
|
|
```
|
||
|
|
+ seller.js : seller apis
|
||
|
|
```javascript
|
||
|
|
const express = require("express");
|
||
|
|
const connection = require("../database");
|
||
|
|
|
||
|
|
SellerRouter = express.Router();
|
||
|
|
|
||
|
|
// localhost:3000/seller/
|
||
|
|
SellerRouter.post("/", (req, res) => {
|
||
|
|
connection.query(
|
||
|
|
`insert into seller (seller_name, seller_wallet) values ('${req.body. name}',${req.body.wallet})`,
|
||
|
|
(err, rows) => {
|
||
|
|
if (err) {
|
||
|
|
console.log(err);
|
||
|
|
res.send("Some error occurred.");
|
||
|
|
} else {
|
||
|
|
res.send("Saved Successfully.");
|
||
|
|
}
|
||
|
|
}
|
||
|
|
);
|
||
|
|
});
|
||
|
|
|
||
|
|
module.exports = SellerRouter;
|
||
|
|
```
|
||
|
|
* sample client fetch
|
||
|
|
```javascript
|
||
|
|
const fetch = require("node-fetch");
|
||
|
|
|
||
|
|
fetch("http://localhost:3000/customer/name/Zixuan", {
|
||
|
|
method: "get",
|
||
|
|
// body: JSON.stringify(
|
||
|
|
// (body = {
|
||
|
|
// name: "dixant",
|
||
|
|
// email: "mittal",
|
||
|
|
// })
|
||
|
|
// ),
|
||
|
|
headers: { "Content-Type": "application/json" },
|
||
|
|
})
|
||
|
|
.then((res) => res.json())
|
||
|
|
.then((json) => console.log(json));
|
||
|
|
```
|
||
|
|
|
||
|
|
* API key
|
||
|
|
|
||
|
|
```javascript
|
||
|
|
|
||
|
|
connection.query(
|
||
|
|
`SELECT * FROM client WHERE client_id = ${request.body.client_id} AND client_key = '${request.body.client_key}'`,
|
||
|
|
(err, result) => {
|
||
|
|
if (ok)
|
||
|
|
serve the request...
|
||
|
|
...
|
||
|
|
}
|
||
|
|
)
|
||
|
|
```
|
||
|
|
|
||
|
|
* Backend server
|
||
|
|
+ formatting conflicting
|
||
|
|
+ flexibility with separation
|
||
|
|
+ separation on client-ui and backend
|