簡體   English   中英

如何在 node js 上實現 csurf 和 react js?

[英]how to implement csurf on node js and react js?

我在node js上有一個react js應用程序,我的應用程序很長時間無法實現csurf,如何以正確的方式實現csurf?

項目目錄

-admin
-client
-config
-middleware
----file.js
----variables.js
-models
-node-modules
-routes
-utils
 index.js
 package-lock.json
 package.json

主節點js文件

index.js

const express = require('express');
const config = require('config');
const path = require('path');
const cookieParser = require('cookie-parser');
const csrf = require('csurf');
const mongoose = require('mongoose');
const helmet = require('helmet');
const compression = require('compression');
const taskRoutes = require('./routes/task');
const performerRoutes = require('./routes/performer');
const categoryRoutes = require('./routes/category');
const authRoutes = require('./routes/auth');
const knowRoutes = require('./routes/know');
const mobileRoutes = require('./routes/mobile');
const statisticsRoutes = require('./routes/statistics');
const businessRoutes = require('./routes/business');
const fileMiddleware = require('./middleware/file');
const varMiddleware = require('./middleware/variables');
const bcrypt = require('bcrypt');
const Admin = require('./models/admin');

const app = express();

const PORT = config.get('port') || 5000;

app.use(express.json({ extended: true }));
app.use(cookieParser());
app.use(csrf({ cookie: {
    httpOnly: true,
    maxAge: 3600 // 1-hour
  }
}));
app.use(varMiddleware);
app.use(fileMiddleware.fields([
    { name: 'avatar', maxCount: 1 },
    { name: 'photosWorks' },
    { name: 'icon', maxCount: 1 }
]));

app.use(helmet());
app.use(helmet.contentSecurityPolicy({
    directives: {
        defaultSrc: ["'self'"],
        scriptSrc: ["'self'", "'unsafe-inline'"],
        styleSrc: ["'self'", "https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css", 
        "https://stackpath.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css", 
        "https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta1/dist/css/bootstrap.min.css"],
        fontSrc: ["'self'", "https://stackpath.bootstrapcdn.com/font-awesome/4.7.0/fonts/"],
        imgSrc: ["'self'"]
    }
}));
app.use(compression());

app.use('/api/category/', categoryRoutes);
app.use('/api/know/', knowRoutes);
app.use('/api/new/task/', taskRoutes);
app.use('/api/performers/', performerRoutes);
app.use('/api/mobile/auth/', mobileRoutes);
app.use('/api/admin/', authRoutes);
app.use('/api/statistics/', statisticsRoutes);
app.use('/api/business/', businessRoutes);

if (process.env.NODE_ENV === 'production') {
    app.use('/', express.static(path.join(__dirname, 'client', 'build')));
    app.use('/', express.static(path.join(__dirname, 'admin', 'build')));

    app.get('/admin/*', (req, res) => {
        res.sendFile(path.resolve(__dirname, 'admin', 'build', 'index.html'))
    });
    app.get('*', (req, res) => {
        res.sendFile(path.resolve(__dirname, 'client', 'build', 'index.html'));
    });
}

async function start() {
    try {
        await mongoose.connect(config.get('mongoUri'), {
            useNewUrlParser: true,
            useUnifiedTopology: true,
            useCreateIndex: true
        });
        const candidate = await Admin.findOne();
        if (!candidate) {
            const hashPassword = await bcrypt.hash('666666', 12);
            const admin = new Admin({
                logAdmin: 'admin1234',
                pasAdmin: hashPassword,
                name: 'Sardor',
                avatarUrl: '/images/cardImg2.jpg'
            });
            await admin.save();
        }
        app.listen(PORT, () => {
            console.log(`Server on port ${PORT}`);
        });
    } catch (e) {
        console.log(e);
    }
}

start();

變量.js

module.exports = function(req, res, next) {
    console.log('varMiddleware');
    res.cookie('XSRF-TOKEN', req.csrfToken());
    next();
}

這是一個反應組件,在這個組件中,我怎樣才能在客戶端正確實現 csurf

for-business-page.js

import React, { Component } from 'react';
import { Link, Redirect } from 'react-router-dom';
import axios from 'axios';

import './for-business-page.css';


class ForBusinessPage extends Component {

    state = {
        name: '',
        phone: '',
        validBusiness: {},
        successBusiness: false
    }

    bidHendler = (e) => {
        e.preventDefault();

        const formData = new FormData(e.target);

        axios.post('/api/business/bid', formData)
            .then((response) => {
                console.log(response);
                this.setState({
                    name: '',
                    phone: '',
                    successBusiness: true
                })
            })
            .catch((err) => {
                const validBusiness = this.validHelper(err.response.data.errors);
                this.setState({ validBusiness });
            })
    }


    validHelper = (arrErrors) => {
        let  validName = '', validPhone = '';
        
        for (let i = 0; i < arrErrors.length; i++) {
            switch (arrErrors[i].param) {
                case 'name':
                    validName = arrErrors[i].msg;
                    break;
                case 'phone':
                    validPhone = arrErrors[i].msg;
                    break;
                default:
                    continue;
            }
        }

        return {
            validName,
            validPhone
        };
    }

    inputControl = (e) => {
        switch (e.target.name) {
            case 'name':
                this.setState({ name: e.target.value });
                break;
            case 'phone':
                this.setState({ phone: e.target.value });
                break;
            default:
                this.setState({ name: '', phone: '' });
        }
    }

    render() {
        const { name, phone, successBusiness } = this.state;

        if (successBusiness) {
            return <Redirect to="/success" />
        }

        return (
            <div className="for-business-page">
                <div className="container-fluid">
                    <div className="hat-business container">
                        <h1>Доставка для бизнеса</h1>
                        <p>Yams.uz осуществляет экспресс-доставку в мегаполисах, быстро, точно и надежно.</p>
                        <p>Курьеры доставят ваши посылки в любую погоду, праздники и выходные. Yams.uz — это курьерская служба к платформе которой, подключены сотни клиентов и десятки тысяч исполнителей.</p>
                        <a href="#bid" className="btn btn-primary">Отправить заявку</a>
                    </div>
                    <div className="bg-img-business">
                        <div className=" container">
                            <div />
                        </div>
                    </div>
                    <div className="business">
                        <div className="container">
                            <h2>Для вашего бизнеса</h2>
                            <div className="row">
                                <div className="col-12 mb-3 col-sm-10 mb-sm-3 offset-sm-1 col-md-6 offset-md-0 col-lg-4 mb-lg-0">
                                    <div className="card">
                                        <img src="/images/card-1.jpg" className="card-img-top" alt="для вашего бизнеса, одежда" />
                                        <div className="card-body">
                                            <h5 className="card-title">Для вашего бизнеса, Одежда</h5>
                                            <p className="card-text">Some quick example text to build on the card title and make up the bulk of the card's content.</p>
                                            <Link to="/" className="btn btn-block btn-primary">Подробнее</Link>
                                        </div>
                                    </div>
                                </div>
                                <div className="col-12 mb-3 col-sm-10 mb-sm-3 offset-sm-1 col-md-6 offset-md-0 col-lg-4 mb-lg-0">
                                    <div className="card">
                                        <img src="/images/card-2.jpg" className="card-img-top" alt="аптеки" />
                                        <div className="card-body">
                                            <h5 className="card-title">Аптеки</h5>
                                            <p className="card-text">Some quick example text to build on the card title and make up the bulk of the card's content.</p>
                                            <Link to="/" className="btn btn-block btn-primary">Подробнее</Link>
                                        </div>
                                    </div>
                                </div>
                                <div className="col-12 mb-3 col-sm-10 mb-sm-3 offset-sm-1 col-md-6 offset-md-0 col-lg-4 mb-lg-0">
                                    <div className="card">
                                        <img src="/images/card-3.jpg" className="card-img-top" alt="рассылка" />
                                        <div className="card-body">
                                            <h5 className="card-title">Рассылка</h5>
                                            <p className="card-text">Some quick example text to build on the card title and make up the bulk of the card's content.</p>
                                            <Link to="/" className="btn btn-block btn-primary">Подробнее</Link>
                                        </div>
                                    </div>
                                </div>
                            </div>
                        </div>
                    </div>
                    <div className="send-bid" id="bid">
                        <div className="container">
                            <h2>Отправить заявку</h2>
                            <p>Заполните данную форму и наши специалисты свяжутся 
                                с вами в кратчайшие сроки, чтобы проконсультировать 
                                вас о наших возможностях, предложить решение и подключить к системе</p>
                            <div className="row">
                                <div className="col-12 col-lg-6">
                                    <div className="bid-form">
                                        <form onSubmit={this.bidHendler}>
                                            <input type="text"
                                            className="form-control form-control-lg mb-3" 
                                            placeholder="Как вас зовут"
                                            name="name"
                                            onChange={this.inputControl}
                                            value={name} />
                                            <input type="phone"
                                            className="form-control form-control-lg mb-3" 
                                            placeholder="Введите номер телефона"
                                            name="phone"
                                            onChange={this.inputControl}
                                            value={phone} />
                                            <button type="submit" 
                                            className="btn btn-lg btn-block btn-business">Отправить заявку</button>
                                        </form>
                                    </div>
                                </div>
                            </div>
                            <div className="bid-form-footer">
                                <p>или позвоните нам по телефону:</p>
                                <p>+998 (90) 777-77-77</p>
                                <p>(Пн — Вс, 9:00 – 21:00)</p>
                            </div>
                        </div>
                    </div>
                </div>
            </div>
        )
    }
}

export default ForBusinessPage;

請幫忙解決一下,不勝感激!

你試過這個嗎? 這包含有關使用 react 保護 express 的完整信息。

https://medium.com/@dbillinghamuk/csrf-setup-for-expressjs-and-ssr-react-redux-app-348e65261009

生成 csurf 令牌並將其設置為 cookie。

為此,請將客戶端路由替換為

app.use(
  '/',    
  (req, res, next) => {
    res.cookie('csrf-token', req.csrfToken());
    next();
  },
  express.static(path.join(__dirname, 'client', 'build'))
);

在 React Component 的構造函數中,從 cookie 中讀取 csurf token

import cookie from 'react-cookies';
...
constructor(props) {
    super(props);
    this.csrf = cookie.load('csrf-token');
}

現在您可以將令牌與請求一起發送到 header

axios.post('/api/business/bid', formDatam, headers: { 
  'csrf-token': this.csrf 
})
    .then((response) => {
        console.log(response);
        this.setState({
            name: '',
            phone: '',
            successBusiness: true
        })
    })
    .catch((err) => {
        const validBusiness = this.validHelper(err.response.data.errors);
        this.setState({ validBusiness });
    })

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM