【发布时间】:2020-09-24 16:18:01
【问题描述】:
我正在构建一个简单的日程安排模块,我将允许任何人访问网站通过日程安排程序提交约会。
在调度程序模块中,我有以下内容:
- 预约以 30 分钟为增量,例如,如果预约在上午 9:00 进行,则预约时间为上午 9:00 至上午 9:30。
- 我正在存储根据用户输入安排的约会中的个人信息,例如电话号码、电子邮件地址、全名
- 在用户提交日程安排后,我运行 SQL 选择语句,它从 MYSQL DB 中获取已安排约会中的所有数据到日程安排程序组件中,以便用户可以查看已进行哪些约会以及在指定时间。
这很好用,但我有点担心,当我将它推送到生产环境时,我注意到在我的网络请求中,我可以看到从数据库中获取的所有数据。允许任何人通过网络请求查看获取的包含个人信息的数据,这可能是一个安全问题吗?
所以我的问题是如何防止这种情况发生?
这是我的代码:
ReactJS
import React, { Component } from 'react';
import appController from '../../controllers/appController';
import Scheduleservice from '../../services/Scheduleservice';
import { withRouter } from "react-router-dom";
import { Helmet } from 'react-helmet';
import Moment from 'moment';
import AOS from 'aos'; // Animate on scroll
import {
ScheduleComponent,
ResourcesDirective,
ResourceDirective,
ViewsDirective,
ViewDirective,
Inject,
TimelineViews,
Resize,
DragAndDrop,
TimelineMonth,
Day,
Week,
WorkWeek,
Month,
Agenda
} from '@syncfusion/ej2-react-schedule';
import { DateTimePickerComponent } from '@syncfusion/ej2-react-calendars';
import { DropDownListComponent } from '@syncfusion/ej2-react-dropdowns';
import { DataManager, WebApiAdaptor, ODataV4Adaptor } from '@syncfusion/ej2-data';
//import * as dataSource from './datasource.json';
class Voipcall extends Component {
constructor(props) {
super(props);
this.dataManager = new DataManager({
url: '/api/selectSchedule',
adaptor: new WebApiAdaptor,
})
this.state = {
scheduleData: [],
employeeData: [
{
Text: 'Facility Appointment',
Id: 1,
GroupId: 1,
Color: '#9e5fff',
Designation: 'Schedule an appointment',
},
],
};
}
onActionBegin(args) {
//console.log('data sent after insertion', args);
if(args.requestType === 'eventCreate' || args.requestType === 'eventChange') {
let data = args.data instanceof Array ? args.data[0] : args.data;
//console.log('Original Data', data);
// If Subject is blank
if(data.Subject !== 'Add title') {
//console.log('subject is blank')
// Format the data Role Id is guest which is 3
let insertData = {
RoleId: undefined ? "3" : "3",
Subject: data.Subject === undefined ? null : data.Subject,
FullName: data.fullName === undefined ? null : data.fullName,
Resident: data.resident === undefined ? null : data.resident,
CommunicationInfo: data.communicationInfo === undefined ? null : data.communicationInfo,
CommunicationMethod: data.communicationMethod === undefined ? null : data.communicationMethod,
Email: data.email === undefined ? null : data.email,
Phone: data.phone === undefined ? null : data.phone,
StartTime: data.StartTime === undefined ? null : appController.converttoISO(data.StartTime),
EndTime: data.EndTime === undefined ? null : appController.converttoISO(data.EndTime),
Description: data.Description === undefined ? null : data.Description
}
console.log('data insertion', insertData)
// Insert Schedule Data into DB
const insertSchedule = Scheduleservice.insertSchedule(insertData);
// Refresh the scheduler
this.props.history.push({
pathname: '/voipCall',
});
}
}
}
onEventRendered(args) {
console.log("Start time ", Moment(args.data.startTime).format());
console.log("End time ", Moment(args.data.endTime).format());
if(args.element.innerText !== 'Not Available') {
args.element.style.backgroundColor = '#0CA6C4';
args.element.innerText = 'Appointment Booked';
}
if(args.element.innerText === 'Not Available') {
args.element.style.backgroundColor = '#ccc';
}
if(args.element.innerText === 'Appointment Booked') {
args.element.style.backgroundColor = '#09A6CA';
}
}
getEmployeeName(value) {
return value.resourceData[value.resource.textField];
}
getEmployeeImage(value) {
let resourceName = this.getEmployeeName(value);
return resourceName.toLowerCase();
}
getEmployeeDesignation(value) {
return value.resourceData.Designation;
}
resourceHeaderTemplate(props) {
return (
<div className='template-wrap'>
<div className='employee-category'>
<div
className={'employee-image ' + this.getEmployeeImage(props)}
></div>
<div className='employee-name'>{this.getEmployeeName(props)}</div>
<div className='employee-designation'>
{this.getEmployeeDesignation(props)}
</div>
</div>
</div>
);
}
editorTemplate(props) {
return props !== undefined ? (
<table
className='custom-event-editor'
style={{ width: '100%', cellpadding: '5' }}
>
<tbody>
<tr>
<td className='e-textlabel'>Meeting Name</td>
<td style={{ colspan: '4' }}>
<input
id='Summary'
className='e-field e-input'
type='text'
name='Subject'
style={{ width: '100%' }}
placeholder='Event Name...'
/>
</td>
</tr>
<tr>
<td className='e-textlabel'>Full Name</td>
<td style={{ colspan: '4' }}>
<input
id='fullName'
className='e-field e-input'
type='text'
name='fullName'
style={{ width: '100%' }}
placeholder='Full Name'
/>
</td>
</tr>
<tr>
<td className='e-textlabel'>Resident Requesting to Speak to</td>
<td style={{ colspan: '4' }}>
<input
id='resident'
className='e-field e-input'
type='text'
name='resident'
style={{ width: '100%' }}
placeholder='Resident you wish to speak to...'
/>
</td>
</tr>
<tr>
<td className='e-textlabel'>Preferred Method of Communication</td>
<td style={{ colspan: '4' }}>
<DropDownListComponent
id='communicationMethod'
placeholder='Choose Method of Communication'
data-name='communicationMethod'
className='e-field'
style={{ width: '100%' }}
dataSource={['Zoom', 'Skype', 'Facetime', 'Viber']}
></DropDownListComponent>
</td>
</tr>
<tr>
<td className='e-textlabel'>Communication Information</td>
<td style={{ colspan: '4' }}>
<input
id='communicationInfo'
className='e-field e-input'
type='text'
name='communicationInfo'
style={{ width: '100%' }}
placeholder='Communication ID'
/>
</td>
</tr>
<tr>
<td className='e-textlabel'>Email Address</td>
<td style={{ colspan: '4' }}>
<input
id='email'
className='e-field e-input'
type='email'
name='email'
style={{ width: '100%' }}
placeholder='Email Address'
/>
</td>
</tr>
<tr>
<td className='e-textlabel'>Phone Number ex: 123456789</td>
<td style={{ colspan: '4' }}>
<input
id='phone'
className='e-field e-input'
type='tel'
name='phone'
style={{ width: '100%' }}
placeholder='Phone Number'
/>
</td>
</tr>
<tr>
<td className='e-textlabel'>From</td>
<td style={{ colspan: '4' }}>
<DateTimePickerComponent
id='StartTime'
format='MM/dd/yy hh:mm a'
data-name='StartTime'
value={new Date(props.startTime || props.StartTime)}
className='e-field'
disabled
></DateTimePickerComponent>
</td>
</tr>
<tr>
<td className='e-textlabel'>To</td>
<td style={{ colspan: '4' }}>
<DateTimePickerComponent
id='EndTime'
format='MM/dd/yy hh:mm a'
data-name='EndTime'
value={new Date(props.endTime || props.EndTime)}
className='e-field'
disabled
></DateTimePickerComponent>
</td>
</tr>
<tr>
<td className='e-textlabel'>Reason</td>
<td style={{ colspan: '4' }}>
<textarea
id='Description'
className='e-field e-input'
name='Description'
rows={3}
cols={50}
style={{
width: '100%',
height: '60px !important',
resize: 'vertical',
}}
></textarea>
</td>
</tr>
</tbody>
</table>
) : (
<div></div>
);
}
fetchSchedule = async () => {
const selectSchedule = await Scheduleservice.selectSchedule();
await this.setState({
scheduleData: selectSchedule
})
//console.log("Schedule Data State is ", this.state.scheduleData);
//console.log("Local Datasource is ", dataSource.scheduleData);
//console.log("state is ", this.state)
}
componentDidMount = async () => {
await this.fetchSchedule();
}
render() {
const { match, location, history } = this.props;
return (
<div className='voipContainer'>
<div className='fluid-container'>
<div className='container'>
<div className='row'>
<div className='schedule-control-section'>
<div className='col-lg-12 control-section'>
<div className='control-wrapper drag-sample-wrapper'>
<div className='schedule-container'>
<ScheduleComponent
//ref={(schedule) => (this.scheduleObj = schedule)}
//ref={(schedule) => console.log("Schedule Data is", schedule)}
cssClass='block-events'
width='100%'
height='650px'
selectedDate={new Date()}
minDate={appController.previousDay(new Date())}
showTimeIndicator={false}
currentView='Day'
resourceHeaderTemplate={this.resourceHeaderTemplate.bind(
this
)}
actionBegin={this.onActionBegin.bind(this)}
eventSettings={{
dataSource: this.dataManager,
}}
eventRendered={this.onEventRendered.bind(this)}
// group={{
// enableCompactView: false,
// resources: ['Employee'],
// }}
//readonly={true}
timeScale={{ enable: true, interval: 30, slotCount: 1 }}
editorTemplate={this.editorTemplate.bind(this)}
>
<ResourcesDirective>
<ResourceDirective
field='EmployeeId'
title='Employees'
name='Employee'
allowMultiple={true}
dataSource={this.state.employeeData}
textField='Text'
idField='Id'
colorField='Color'
></ResourceDirective>
</ResourcesDirective>
<ViewsDirective>
<ViewDirective option='Day' />
<ViewDirective option='TimelineDay' />
</ViewsDirective>
<Inject
services={[
Day, Week, WorkWeek, Month, Agenda
]}
/>
</ScheduleComponent>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
);
}
}
export default withRouter(Voipcall);
MYSQL 语句
var db = require('../dbconnection');
var schedule = {
selectSchedule: function (data, callback) {
db.query(
'select Id, Role_Id, Subject, Location, StartTime, EndTime, Description, Owner, Priority, Recurrence, RecurrenceType, RecurrenceTypeCount, Reminder, Categorize, CustomStyle, AllDay, RecurrenceStartDate, RecurrenceEndDate, RecurrenceRule, StartTimeZone, EndTimeZone, IsBlock, isSlotAvailable, FullName, Resident, CommunicationMethod, CommunicationInfo, Email, Phone, Reason from schedule',
callback
);
},
insertSchedule: function(data, callback) {
db.query('insert schedule set Role_Id=?, Subject=?, FullName=?, Resident=?, CommunicationMethod=?, CommunicationInfo=?, Email=?, Phone=?, Reason=?, IsBlock=?, StartTime=?, EndTime=?', [data.RoleId, data.Subject, data.FullName, data.Resident, data.CommunicationMethod, data.CommunicationInfo, data.Email, data.Phone, data.Description, "true", data.StartTime, data.EndTime], callback)
//console.log('data got sent to backend', data);
}
};
module.exports = schedule;
网络请求屏幕截图以及 JSON 响应:
[
{
"Id":1,
"Role_Id":null,
"Subject":"Bering Sea Gold DB Test",
"Location":"chn",
"StartTime":"2020-09-23T09:00:00",
"EndTime":"2020-09-23T10:30:00",
"Description":"",
"Owner":1,
"Priority":null,
"Recurrence":1,
"RecurrenceType":null,
"RecurrenceTypeCount":null,
"Reminder":null,
"Categorize":"1,2",
"CustomStyle":null,
"AllDay":"false",
"RecurrenceStartDate":null,
"RecurrenceEndDate":null,
"RecurrenceRule":"FREQ=DAILY;INTERVAL=2;COUNT=10",
"StartTimeZone":null,
"EndTimeZone":null,
"IsBlock":"",
"isSlotAvailable":null,
"FullName":null,
"Resident":null,
"CommunicationMethod":null,
"CommunicationInfo":null,
"Email":null,
"Phone":null,
"Reason":null
},
{
"Id":2,
"Role_Id":null,
"Subject":"Not Available",
"Location":null,
"StartTime":"2020-08-01T03:00:00.000Z",
"EndTime":"2020-08-01T09:00:00.000Z",
"Description":null,
"Owner":null,
"Priority":null,
"Recurrence":0,
"RecurrenceType":null,
"RecurrenceTypeCount":null,
"Reminder":null,
"Categorize":null,
"CustomStyle":null,
"AllDay":null,
"RecurrenceStartDate":null,
"RecurrenceEndDate":null,
"RecurrenceRule":"FREQ=DAILY;INTERVAL=1;",
"StartTimeZone":null,
"EndTimeZone":null,
"IsBlock":"true",
"isSlotAvailable":null,
"FullName":null,
"Resident":null,
"CommunicationMethod":null,
"CommunicationInfo":null,
"Email":null,
"Phone":null,
"Reason":null
},
{
"Id":22,
"Role_Id":3,
"Subject":"Test Appointment 1",
"Location":null,
"StartTime":"2020-09-24T14:30:00.000Z",
"EndTime":"2020-09-24T15:00:00.000Z",
"Description":null,
"Owner":null,
"Priority":null,
"Recurrence":0,
"RecurrenceType":null,
"RecurrenceTypeCount":null,
"Reminder":null,
"Categorize":null,
"CustomStyle":null,
"AllDay":null,
"RecurrenceStartDate":null,
"RecurrenceEndDate":null,
"RecurrenceRule":null,
"StartTimeZone":null,
"EndTimeZone":null,
"IsBlock":"true",
"isSlotAvailable":null,
"FullName":"John Doe",
"Resident":"Alex West",
"CommunicationMethod":"Facetime",
"CommunicationInfo":"test@test.com",
"Email":"test@test.com",
"Phone":"999999999",
"Reason":"This is a test Module."
},
{
"Id":23,
"Role_Id":3,
"Subject":"Test Appointment 2",
"Location":null,
"StartTime":"2020-09-24T18:30:00.000Z",
"EndTime":"2020-09-24T19:00:00.000Z",
"Description":null,
"Owner":null,
"Priority":null,
"Recurrence":0,
"RecurrenceType":null,
"RecurrenceTypeCount":null,
"Reminder":null,
"Categorize":null,
"CustomStyle":null,
"AllDay":null,
"RecurrenceStartDate":null,
"RecurrenceEndDate":null,
"RecurrenceRule":null,
"StartTimeZone":null,
"EndTimeZone":null,
"IsBlock":"true",
"isSlotAvailable":null,
"FullName":"Jason Stride",
"Resident":"Chris Thomson",
"CommunicationMethod":"Facetime",
"CommunicationInfo":"test2@test.com",
"Email":"test2@test.com",
"Phone":"999999999",
"Reason":"This is test appointment 2"
}
]
【问题讨论】:
标签: mysql node.js reactjs security