본문 바로가기

개발

[WEB] Node.js 웹 사이트 구축 4 (게시판 구현)

※해당 게시글은 취약점 진단 목적의 웹 서비스 구축을 위한 부분으로, 일반적인 웹 서비스 개발 목적과는 다름을 참고해주시면 감사하겠습니다.

※일반적으로는 게시판 등의 기능을 구현하고 HTTPS 설정을 할 수 있으나, 개발 목적 상 초기에는 로그인 기능까지만 필요하였기에 HTTPS 설정을 우선함

※차후 테스트 목적으로 파일 업로드 등을 포함한 게시판 기능이 일부 필요하여 추가 진행

 

1.구축 환경

구분 설명 비고
운영체제 Ubuntu 22.04 x64 (6.2.0-36-generic)  
하드웨어 VM  
서버 운영환경 Node v12.22.9 / npm 8.5.1 / express 4.18.2
mongoose 8.0.3
ejs 3.1.9


데이터베이스  MongoDB Community Edition 7.0.4  

 

 

2.구축 과정

1)게시판 필요 기능 구분

(1) 게시글 전체 목록 표시

필요 기능 설명 및 요구 사항
게시글 목록 번호 / 제목 / 작성자 / 작성일의 정보로 표시되는 전체 게시글 목록
'제목' 선택으로, 게시글 열람
글쓰기 버튼 '글쓰기' 버튼 선택으로, 게시글 쓰기 기능으로 이동

 

(2) 게시글 쓰기

필요 기능 설명 및 요구 사항
제목 쓰기 게시글의 제목을 입력받기 위한 기능
내용 쓰기 게시글의 내용을 입력받기 위한 기능
파일 업로드 게시글에 포함될 첨부 파일 업로드 기능

 

(3) 게시글 열람

필요 기능 설명 및 요구 사항
제목 표시 작성된 게시글의 제목 표시
내용 표시 작성된 게시글의 내용 표시
첨부파일 표시 작성된 게시글에 포함된 첨부파일명 표시
파일 다운로드 작성된 게시글에 포함된 첨부파일 다운로드

 

2) 게시글 전체 목록 표시 구현

(1) 소스코드

// 게시판 라우트
app.get('/board', requireLogin, async (req, res) => {

  try {
    // MongoDB 클라이언트 연결
    await client.connect();

    // 'WebApplication_01' 데이터베이스 및 'Posts' 컬렉션 선택
    const database = client.db('WebApplication_01');
    const postsCollection = database.collection('Posts');

    // 최근 작성된 게시글 중 최대 10개 가져오기
    const posts = await postsCollection.find().sort({ timestamp: -1 }).limit(10).toArray();

    // 게시판 템플릿 렌더링
    res.render('board', { posts });
  } catch (error) {
    console.error('게시글 조회 오류:', error);
    res.status(500).send('서버 오류');
  } finally {
    // MongoDB 클라이언트 연결 종료
    await client.close();
  }
});

(2) 예시

간략한 게시글 전체 보기

 

3)게시글 쓰기

(1) 소스코드

app.post('/board_write', upload.single('file'), requireLogin, async (req, res) => {
  const { title, content } = req.body;
  const uploadedFile = req.file;

  try {
    // MongoDB 클라이언트 연결
    await client.connect();

    // 'WebApplication_01' 데이터베이스 및 'Posts' 컬렉션 선택
    const database = client.db('WebApplication_01');
    const postsCollection = database.collection('Posts');

    // 새로운 게시글 생성
    const newPost = {
      title,
      content,
      author: req.session.user,
      timestamp: new Date(),
      file: uploadedFile ? uploadedFile.originalname : null,
    };

    // 데이터베이스에 새로운 게시글 삽입
    await postsCollection.insertOne(newPost);

    // 게시판 페이지로 리다이렉트
    res.redirect('/board');
  } catch (error) {
    console.error('게시글 작성 오류:', error);
    res.status(500).send('서버 오류');
  } finally {
    // MongoDB 클라이언트 연결 종료
    await client.close();
  }
});

(2) 예시

글쓰기 예시

 

4)게시글 열람

(1) 소스코드

// 게시글 보기 페이지
app.get('/board/:postId', requireLogin, async (req, res) => {
  
  const postId = req.params.postId;
  console.log('Requested Post ID:', postId);
  //게시글 ID를 Object 타입으로 재선언
  const postIdObject = new ObjectId(postId);

  try {
    // MongoDB 클라이언트 연결
    await client.connect();

    // 'WebApplication_01' 데이터베이스 및 'Posts' 컬렉션 선택
    const database = client.db('WebApplication_01');
    const postsCollection = database.collection('Posts');

    // postId에 해당하는 게시글 조회
    //const post = await postsCollection.findOne({ _id: postId });
	const post = await postsCollection.findOne({ _id: postIdObject });
	console.log('Requested Post :', post); // 이 부분을 추가
    if (post) {
      res.render('view_post', { post });
    } else {
      res.status(404).send('게시글을 찾을 수 없습니다.');
    }
  } catch (error) {
    console.error('MongoDB 연결 오류:', error);
    res.status(500).send('서버 오류');
  } finally {
    // MongoDB 클라이언트 연결 종료
    await client.close();
  }
});

 

(2) 예시

게시글 열람 예시

 

 

3.예외 처리

1) 게시글이 난수 값으로 생성되는 ObjectId로 링크가 생성되는 점은 확인하였으나, 개발 목적 상 현재 필요한 부분이 아니기에 수정하지 않음

2) 업로드되는 파일명, 다운로드 링크 정보 및 업로드된 Node 서버 내 저장되는 파일명이 원본 파일명으로 저장되나 개발 목적 상 수정하지 않음

서버 내 저장된 업로드된 파일 목록

3) 업로드된 파일 중 일부 파일은 사용자 환경에서 실행되는 부분으로 취약점이 발생하나 개발 목적 상 수정하지 않음

첨부 파일 선택 시, 입력된 값이 실행됨