1. 기본 환경 설정

 1) https://start.spring.io/ 에서 spring initializr 를 사용하여 프로젝트를 구성하고 GENERATE로 생성한다

프로젝트 설정

 2) IntelliJ를 열고 프로젝트 파일을 오픈한다

  • 생성된 파일을 지정 폴더에 압축풀기를 한다
  • 압축을 푼 폴더에서 build 파일을 intelliJ에서 오픈한다

 3) 의존성을 설정한다

  • build.gradle 파일을 열고 아래와 같이 코드를 작성한다
plugins {
	id 'org.springframework.boot' version '2.7.1'
	id 'io.spring.dependency-management' version '1.0.11.RELEASE'
	id 'java'
}

group = 'com.codestates'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '11'

repositories {
	mavenCentral()
}

dependencies {
	annotationProcessor 'org.projectlombok:lombok'
	implementation 'org.springframework.boot:spring-boot-starter-security'
	implementation 'org.springframework.boot:spring-boot-starter-web'
	implementation 'org.springframework.boot:spring-boot-starter-mustache'
	implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
	implementation 'org.projectlombok:lombok'
	implementation 'org.springframework.boot:spring-boot-starter-data-jdbc'
	runtimeOnly 'com.h2database:h2'
}

tasks.named('test') {
	useJUnitPlatform()
}

  • gradle 에서 코드를 추가하거나 수정한 후에는 Gradle 탭에서 Reload를 해 준다

 

 3) db.jpa 설정을 추가한다

  • resource 폴더 아래에 application.yml 파일을 추가한다
spring:
  h2:
    console:
      enabled: true
      path: /h2
  datasource:
    url: jdbc:h2:mem:test
  jpa:
    hibernate:
      ddl-auto: create
    show-sql: true

 

 4) 애플리케이션 출력 화면을 구성하기 위해 2개의 파일을 추가한다

  • src/resources/templates 아래에 추가한다
  • loginForm.html
    - 로그인 화면에 출력되는 HTML 코드이다
<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>로그인 페이지</title>
</head>
<body>
<h1>로그인 페이지</h1>
<hr />
<form action="/login" method="post">
    <input type="text" name="username" placeholder="Username" /><br />
    <input type="password" name="password" placeholder="Password" /><br />
    <button>로그인</button>
</form>
<a href="join">회원가입</a>
</body>
</html>
  • joinForm.html
    - 회원가입 화면에 출력되는 HTML 코드이다
<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>회원가입 페이지</title>
</head>
<body>
<h1>회원가입 페이지</h1>
<hr />
<form action="/join" method="post">
  <input type="text" name="username" placeholder="Username" /><br />
  <input type="password" name="password" placeholder="Password" /><br />
  <input type="email" name="email" placeholder="Email" /><br />
  <button>회원가입</button>
</form>
</body>
</html>

 

2. 기본 실행

 1) 애플리케이션을 실행한다

  • intelliJ에서 프로젝트를 실행한다
  • 콘솔 화면에 아래와 같이 password가 부여되고 설명이 출력되면 기본 설정이 적용된 것이다

  • http://localhost:8080 으로 접속한다

  • Username : user / password : 콘솔창에 표시된 password 를 작성한다
  • 현재 login 화면 구성이 없기 때문에 Error 메시지가 출력될 것이다

 

3. Spring Security Configuration 적용

 1) src > main > java > com.memberlogin.loginjoin 아래에 controller 패키지와 IndexController.java를 생성한다

  • 코드 생성 후 반드시 애플리케이션을 재실행 한다
package com.memberlogin.loginjoin.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
public class IndexController {

    @GetMapping("/")
    public @ResponseBody String index() {
        return "index";
    }

    @GetMapping("/user")
    public @ResponseBody String user() {
        return "user";
    }

    @GetMapping("/admin")
    public @ResponseBody String admin() {
        return "admin";
    }

    @GetMapping("/manager")
    public @ResponseBody String manager() {
        return "manager";
    }

    @GetMapping("/login")
    public @ResponseBody String login() {
        return "login";
    }

    @GetMapping("/join")
    public @ResponseBody String join() {
        return "join";
    }
}
  • 애플리케이션을 재실행 후 web 접속하여 로그인을 하면 아래와 같이 출력된다
    - url을 지정하지 않은 경우에 출력은 'index'로 설정되어 있다

  • 총 5개의 url을 설정하였고 5개 중 1개의 url을 제외하고는 모두 로그인 시 정상적으로 작동하는 것을 확인할 수 있다
    - /login의 경우에는 Spring Security가 처리하고 있기 때문에 작동하지 않는다
localhost:8080/login localhost:8080/user localhost:8080/admin localhost:8080/manager localhost:8080/join

 

 2) src > main > java > com.memberlogin.loginjoin 아래에 config 패키지와 SecurityConfig.java를 생성한다

  • @Configuration과 @EnableWebSecurity를 추가한다
    - @EnableWebSecurity 추가 시 스프링 시큐리티 필터가 스프링 필터체인에 등록 된다
  • filterChain 메서드를 @Bean으로 등록한 후 스프링 컨테이너에서 관리할 수 있도록 한다
  • http.csrf().disable(); 의 경우에는 form 태그로만 요청이 가능해지고 postman등의 요청이 불가능하게 된다
    - csrf를 disable 한다
  • http.headers().frameOptions().disable(); 은 h2 연결할 때 필요하다
  • Config 설정이 되면  /login에 접속이 가능하게 된다
package com.memberlogin.loginjoin.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.web.SecurityFilterChain;

@Configuration
@EnableWebSecurity
public class SecurityConfig {

    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http.csrf().disable();
				http.headers().frameOptions().disable();

        http.authorizeRequests()
                .antMatchers("/user/**").authenticated()
                .antMatchers("/manager/**").access("hasRole('ROLE_ADMIN') or hasRole('ROLE_MANAGER')")
                .antMatchers("/admin/**").access("hasRole('ROLE_ADMIN')")
                .anyRequest().permitAll();
        return http.build();
    }

}
  • 애플리케이션을 재실행 후 web 접속하여 로그인을 하면 아래와 같이 출력된다
    - http://localhost:8080 으로 접속하면 index 가 표시되고
    - http://localhost:8080/login 으로 접속하면 login 이 표시된다
  • /, /login, /join 3개의 url은 로그인 없이도 접속이 가능하다

  • /admin, /manager url의 경우에는 권한이 없기 때문에 403 에러가 출력된다

admin, manager 접속 시 콘솔창에 session ID가 생성되는 것을 볼 수 있다

  • 아래 코드를 추가한 후 재실행하고 접속하면 로그인이 가능해 진다
    - admin 과 manager 로 접속 시 login이 출력된다
                .and()
                .formLogin()
                .loginPage("/login");

 

 3) config 패키지 아래에 WebMvcConfig.java를 생성한다

  • mustache → html 사용할 수 있도록 설정한다
package com.memberlogin.loginjoin.config;

import org.springframework.boot.web.servlet.view.MustacheViewResolver;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ViewResolverRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class WebMvcConfig implements WebMvcConfigurer {

    @Override
    public void configureViewResolvers(ViewResolverRegistry registry) {
        MustacheViewResolver resolver = new MustacheViewResolver();
        resolver.setCharset("UTF-8");
        resolver.setContentType("text/html; charset=UTF-8");
        resolver.setPrefix("classpath:/templates/");
        resolver.setSuffix(".html");

        registry.viewResolver(resolver);
    }
}
  • ViewResolver 구현 클래스 종류

 4) src > main > java > com.memberlogin.loginjoin 아래에 model 패키지와 Member.java를 생성한다

package com.memberlogin.loginjoin.model;

import lombok.Data;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import java.time.LocalDateTime;

@Entity
@Data
public class Member {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String username;
    private String password;
    private String email;
    private String role;
    private LocalDateTime createdAt = LocalDateTime.now();
}

 

 5) src > main > java > com.memberlogin.loginjoin 아래에 repository 패키지와 MemberRepository.java를 생성한다

package com.memberlogin.loginjoin.repository;

import com.memberlogin.loginjoin.model.Member;
import org.springframework.data.jpa.repository.JpaRepository;

public interface MemberRepository extends JpaRepository<Member, Long> {
}

 

4. 회원 가입

 1) 회원가입에 필요한 코드를 수정한다

  • controller 패키지의 IndexController 클래스를 수정한다
  • 코드를 수정하고 실행하면 정상적으로 db에 저장되게 된다
@Controller
public class IndexController {

    @Autowired
    MemberRepository memberRepository;

		...

    @GetMapping("/login")
    public String login() {
        return "loginForm";
    }

    @GetMapping("/join")
    public String joinForm() {
        return "joinForm";
    }

    @PostMapping("/join")
    public @ResponseBody String join(Member member) {

        member.setRole("ROLE_USER");
        memberRepository.save(member);
        return "join";
    }
}

  • 애플리케이션을 재실행하면 아래와 같이 로그인 페이지가 정상적으로 출력되고 로그인 시 index 가 출력된다

 

 2) 패스워드 암호화를 위한 코드 수정

  • config 패키지의 SecurityConfig 클래스를 수정한다
    - 아래 이미지에 @Bean 이 한 곳 빠져 있다...이 오류 때문에 고생 많이 했다...그래서 이미지를 수정하지 않고 둔다..^^
    - @Autowired
        private BCryptPasswordEncoder bCryptPasswordEncoder;
        -> IndexController 클래스의 Bean 충돌로 인하여 서버 실행에 에러가 발생한다.
        -> 주석 처리해 주면 해결된다
public class SecurityConfig {
		
    @Autowired
    private BCryptPasswordEncoder bCryptPasswordEncoder;
    
    ...

    @Bean // 추가
    public BCryptPasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }
		
    ...
}

  • controller 패키지의 IndexController 클래스를 수정한다
    @PostMapping("/join")
    public String join(Member member) {
        member.setRole("ROLE_USER");
        String rawPassword = member.getPassword();
        String encPassword = bCryptPasswordEncoder.encode(rawPassword);
        member.setPassword(encPassword);

        memberRepository.save(member);

        return "redirect:/login";
    }
  • 애플리케이션 재실행 후 웹에 접속하여 확인한다
  • http://localhost:8080/h2 에 접속하여 입력된 데이터를 확인할 수 있다

 

5. 로그인

 1) config > auth 패키지를 만들고 PrincipalDetails 클래스를 생성한다

  • PrincipalDetails 클래스에 implements UserDetails와 메서드를 오버라이드 한다
  •  org.springframework.security.core.userdetails
    - 보안 목적으로 Spring Security에서 직접 사용되지 않는다
    - 단순히 나중에 객체로 캡슐화되는 사용자 정보를 저장 Authentication 한다
    - 보안과 관련되지 않은 사용자 정보(예: 이메일 주소, 전화번호 등)를 편리한 위치에 저장할 수 있다
 

org.springframework.security.core.userdetails (spring-security-docs 5.7.2 API)

 

docs.spring.io

  • 시큐리티는 /login 주소에 요청이 오면 대신 로그인을 진행한다
  • Authentication 타입 객체이며 안에 Member 정보가 있어야 한다
  • 로그인 진행이 완료되면 security session을 만들어 준다 (Security ContextHolder)
package com.memberlogin.loginjoin.config.auth;

import com.memberlogin.loginjoin.model.Member;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;

import java.util.ArrayList;
import java.util.Collection;

public class PrincipalDetails implements UserDetails {

    private Member member;

    public PrincipalDetails(Member member) {
        this.member = member;
    }

    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        Collection<GrantedAuthority> collection = new ArrayList<>();
        collection.add(new GrantedAuthority() {
            @Override
            public String getAuthority() {
                return member.getRole();
            }
        });
        return collection;
    }

    @Override
    public String getPassword() {
        return member.getPassword();
    }

    @Override
    public String getUsername() {
        return member.getUsername();
    }

    @Override
    public boolean isAccountNonExpired() {
        return true;
    }

    @Override
    public boolean isAccountNonLocked() {
        return true;
    }

    @Override
    public boolean isCredentialsNonExpired() {
        //isCredentialsNonExpired()는 암호 사용 기간이 지났는지 여부를 확인한다
        return true;
    }

    @Override
    public boolean isEnabled() {
        //isEnabled()은 특정 사이트 규칙에 따라 return false로 설정한다
        // ex) 1년 동안 로그인을 하지 않았을 경우
        return true;
    }
}
//현재 따로 규칙이 없기 때문에 isAccountNonExpired, isAccountNonLocked, isCredentialsNonExpired, isEnabled 메서드들을
//모두 return true로 설정한다

 

 2) config > auth 패키지에 PrincipalDetailsService 클래스를 생성한다

  • PrincipalDetailsService에 implement UserDetailsService와 메서드를 오버라이드 한다
  • Security 설정에서 loginProcessingUrl(”/login”);으로 요청이 오면 자동으로 UserDetailsService 타입으로 IoC되어 있는 loadUserByUsername 함수가 실행된다
  • 메서드 파라미터에 username이라고 되어있으면 form을 통해 username을 가져올 때 name이 반드시 매치되야 한다
    - 이름을 똑같이 변경해주거나
    - SecurityConfig에 .loginPage() 아래에 .usernameParameter(”다른 이름")으로 추가해야 한다
  • loadUserByUsername 함수가 Authentication으로 값이 return 된다
package com.memberlogin.loginjoin.config.auth;

import com.memberlogin.loginjoin.model.Member;
import com.memberlogin.loginjoin.repository.MemberRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;

@Service
public class PrincipalDetailsService implements UserDetailsService {

    @Autowired
    private MemberRepository memberRepository;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        Member memberEntity = memberRepository.findByUsername(username);
        System.out.println("username : " + username);
        if(memberEntity != null) {
            return new PrincipalDetails(memberEntity);
        }
        return null;
    }
}

 

 3) MemberRepository에 findByUsername 메서드를 추가해줍니다.

  • PrincipalDetailsService에 있는 loadUserByUsername에서 사용하기 때문에 해당 메서드를 추가한다
  • UserDetailService에서 findByUsername을 구현처리 할 때 자동적으로 생성되지만 한번 더 확인한다

package com.memberlogin.loginjoin.repository;

import com.memberlogin.loginjoin.model.Member;
import org.springframework.data.jpa.repository.JpaRepository;

public interface MemberRepository extends JpaRepository<Member, Long> {
    public Member findByUsername(String username);
}
  • 애플리케이션을 재실행 한 후 웹에 http://local:8080/uesr 접속하여 회원 가입 후 로그인을 진행한다
    - 이상없이 회원가입과 로그인이 진행된다
    - 친절하게 비밀번호에 대한 확인 창도 표시된다
  • localhost:8080/login 과 localhost:8080/join, localhost:8080/user 은 원활하게 접속이 된다
로그인을 실행한 후 화면이다
로그아웃은 하지 않았다



 


  • localhost:8080/admin 과 localhost:8080/manager는 다시 403 에러가 뜨는 것을 확인할 수 있다

 

6. 권한 처리

 1) manager, admin 처리

  • 회원가입 후 h2 database에서 ROLE을 ROLE_ADMIN으로 변경해줍니다.
  • localhost:8080/admin 과 localhost:8080/manager 에 정상적으로 접근이 가능하고 그 외 모든 url 또한 접근이 가능한 것을 확인할 수 있다
  • SecurityConfig 클래스에 코드를 추가한다
@Configuration
@EnableWebSecurity

//권한 처리 추가
@EnableGlobalMethodSecurity(securedEnabled = true, prePostEnabled = true)

/*@EnableGlobalMethodSecurity(securedEnabled = true)
  - Secured 애너테이션이 활성화 된다
  - SecurityConfig에서 접근 권한 설정이 아닌 Controller에서 애너테이션으로 관리할 수 있게 된다*/
  
/*@EnableGlobalMethodSecurity(prePostEnabled=true)
  - PreAuthorize, PostAuthorize 애너테이션이 활성화 된다.*/

public class SecurityConfig {

 

 2) IndexController.java에 새로운 메서드와 @Secured와 @preAuthorize를 추가한다

  //권한 추가
   @Secured("ROLE_ADMIN")
    @GetMapping("/info")
    public @ResponseBody String info() {
        return "info";
    }

    @PostMapping("/join")
    public String join(Member member) {
        member.setRole("ROLE_USER");
        String rawPassword = member.getPassword
  • SecurityConfig에 .antMatchers("/info/**").access("hasRole('ROLE_ADMIN')") 코드를 추가하는 것과 같은 동작이 된다
    - @Secured는 1개의 권한을 주고 싶을 때 사용한다
    - @PreAuthorize는 1개 이상의 권한을 주고 싶을 때 사용한다
      : #을 사용하면 파라미터에 접근할 수 있다
      : ex) @PreAuthorize("isAuthenticated() and (( #user.name == principal.name ) or hasRole('ROLE_ADMIN'))")
    - @PostAuthorize는 메서드가 실행되고 응답하기 직전에 권한을 검사하는데 사용된다
    - 클라이언트에 응답하기 전에 로그인 상태 또는 반환되는 사용자 이름과 현재 사용자 이름에 대한 검사, 현재 사용자가 관리자 권한을 가지고 있는지 등의 권한 후처리를 할 수 있다
	@PreAuthorize("hasRole('ROLE_MANAGER') or hasRole('ROLE_ADMIN')")
    @GetMapping("/data")
    public @ResponseBody String data() {
        return "data";
    }

 

 

※ 참조 링크

BCryptPasswordEncoder :

https://docs.spring.io/spring-security/site/docs/current/api/org/springframework/security/crypto/bcrypt/BCryptPasswordEncoder.html

 

BCryptPasswordEncoder (spring-security-docs 5.7.2 API)

All Implemented Interfaces: PasswordEncoder public class BCryptPasswordEncoder extends java.lang.Object implements PasswordEncoder Implementation of PasswordEncoder that uses the BCrypt strong hashing function. Clients can optionally supply a "version" ($2

docs.spring.io

 

'인증 & 보안' 카테고리의 다른 글

웹 보안 공격  (0) 2022.07.23
보안 - Hashing,Coolie,Seesion  (0) 2022.07.23
인증 - HTTPS  (0) 2022.07.21

1. Spring Security

  • Spring Framework 기반으로 애플리케이션의 인증(Authentication)과 인가(Authorization or 권한 부여) 기능을 가진 프레임워크이다
  • 모든 필수 파일은 애플리케이션에 포함되어 있으며, 애플리케이션이 독립적으로 작동하는 것을 목표로 한다
  • Java Runtime Environment에 특별한 구성 파일을 배치할 필요가 없다
  •  JAAS(Java Authentication and Authorization Service) 정책 파일의 구성이 필요 없다
  • Spring Security를 ​​공통 클래스 경로 위치에 배치하지 않아도 된다
  • 한 시스템에서 다른 시스템으로 대상 아티팩트(JAR, WAR 또는 EAR)를 복사함과 동시에 작동하므로 최대 배포 시간의 유연성을 제공한다
  • Apache 2.0 라이센스 하에 출시된 오픈 소스 소프트웨어이다
  • Java 8 이상의 환경이 필요하다
  • Spring Security는 종속성을 Maven 아티팩트로 배포한다

 

2. Spring Security 용어

  • 주체(Principal)
    - 유저, 기기, 시스템 등이 될 수 있지만, 일반적으로 유저(사용자)를 의미한다
  • 인증(Authentication)
    - 특정 리소스에 접근하려고 하는 사용자가 누구인지 확인하는 경우에 사용한다
    - 주체의 신원(identity)을 증명하는 과정이다
    - 주체는 자신을 인증하기 위해 신원 증명 정보(credential)을 제시한다
    - 주체가 유저일 경우 신원 증명 정보는 패스워드(password)이다
  • 인가(Authorization = 권한 부여)
    - 인증을 마친 유저에게 권한(authority)을 부여하여 애플리케이션의 특정 리소스에 접근할 수 있게 허가하는 과정이다
    - 인가는 반드시 인증 과정 이후 수행되어야 한다
    - 권한은 롤 형태로 부여한다
  • 접근 통제(Access control)
    - 어떤 유저가 애플리케이션 리소스에 접근하도록 허락할지를 제어하는 행위이다
    - 접근 통제 결정(access control decision)이 필요하다
    - 리소스의 접근 속성과 유저에게 부여된 권한 또는 다른 속성들을 결정한다

 

3. Spring Security 제공 기능

  • 모든 요청에 대해서 인증을 요구한다
  • 사용자 이름과 암호를 가진 사용자가 양식 기반으로 인증할 수 있도록 허용한다
  • 사용자의 로그아웃을 허용한다
  • CSRF(Cross-Site Request Forgery) 공격을 방지한다
    - CSRF 공격은 사용자가 자신의 의지와는 무관하게 공격자가 의도한 행위(수정, 삭제, 등록 등)를 특정 웹사이트에 요청하게 하는 공격을 의미한다
  • Session Fixsation(세션 고정 공격)을 보호 한다
    - Session Fixsation은 공격자가 자신의 세션 id를 다른 사용자에게 넘겨주고 공격하게 하는 방법을 의미한다
  • 보안 헤더 통합
    - HSTS 강화
    - X-Content-TypeOptions
    - 캐시 컨트롤(정적 리소스 캐싱)
    - X-XSS-Protection XSS 보안
     : 스크립트 공격 보안
    - 클릭재킹을 방지하는 X-Frame 옵션 통합
     : 클릭재킹이란 웹 사용자가 클릭하고 있는 것에 다른 것을 대체하여 클릭하도록 속이는 기법으로 공격자는 비밀 정보 유출이나 컴퓨터에 대한 제어권을 획득할 수 있게 된다
  • Servlet API 제공

 

 

 

 

※ 참조 링크

Spring Security Tutorial : https://docs.spring.io/spring-security/reference/index.html

 

Spring Security :: Spring Security

If you are ready to start securing an application see the Getting Started sections for servlet and reactive. These sections will walk you through creating your first Spring Security applications. If you want to understand how Spring Security works, you can

docs.spring.io

Spring Security Q&A

 : https://stackoverflow.com/questions/tagged/spring-security

 

Newest 'spring-security' Questions

Stack Overflow | The World’s Largest Online Community for Developers

stackoverflow.com

 : https://github.com/spring-projects/spring-security/issues

 

GitHub - spring-projects/spring-security: Spring Security

Spring Security. Contribute to spring-projects/spring-security development by creating an account on GitHub.

github.com

Spring Security Source Code : https://github.com/spring-projects/spring-security/

 

GitHub - spring-projects/spring-security: Spring Security

Spring Security. Contribute to spring-projects/spring-security development by creating an account on GitHub.

github.com

 HSTS(HTTP Strict Transport Security) 기능

 : https://m.blog.naver.com/PostView.nhn?blogId=aepkoreanet&logNo=221575708943&proxyReferer=https:%2F%2Fwww.google.com%2F 

 

HSTS(HTTP Strict Transport Security) 기능

HSTS(HTTP Strict Transport Security) HSTS(HTTP Strict Transport Security)는, ...

blog.naver.com

클릭재킹 : https://ko.wikipedia.org/wiki/%ED%81%B4%EB%A6%AD%EC%9E%AC%ED%82%B9

 

클릭재킹 - 위키백과, 우리 모두의 백과사전

위키백과, 우리 모두의 백과사전. 클릭재킹(Clickjacking, User Interface redress attack, UI redress attack, UI redressing)은 웹 사용자가 자신이 클릭하고 있다고 인지하는 것과 다른 어떤 것을 클릭하게 속이는

ko.wikipedia.org

 

+ Recent posts