স্প্রিং বুট 2 এবং স্প্রিং সিকিউরিটি 5 সহ মাল্টি-ফ্যাক্টর প্রমাণীকরণ


11

স্প্রিং বুট সুরক্ষা স্টার্টারের ডিফল্টগুলিতে যতটা সম্ভব সম্ভবকে কাছে রেখে আমি একটি কৌণিক এবং স্প্রিং অ্যাপ্লিকেশনটিতে টুপি সফট টোকেনের সাথে মাল্টি-ফ্যাক্টর প্রমাণীকরণ যুক্ত করতে চাই ।

টোকেন-বৈধতা স্থানীয়ভাবে হয় (এয়ারওগার-ওটিপি-জাভা লাইব্রেরির সাথে), কোনও তৃতীয় পক্ষের এপিআই সরবরাহকারী নয়।

কোনও ব্যবহারকারীর জন্য টোকেন সেটআপ করা কাজ করে তবে স্প্রিং সিকিউরিটি অথেনটিকেশন ম্যানেজার / সরবরাহকারীরা সুবিধা দেয় না them

টি এল; ডিআর

  • একটি স্প্রিং বুট সিকিউরিটি স্টার্টার কনফিগার করা সিস্টেমে অতিরিক্ত প্রমাণীকরণের সরবরাহকারীকে সংহত করার আনুষ্ঠানিক উপায় কী ?
  • রিপ্লে আক্রমণ রোধ করার প্রস্তাবিত উপায়গুলি কী কী?

দীর্ঘ সংস্করণ

এপিআই-এর একটি এন্ডপয়েন্ট /auth/tokenরয়েছে যেখানে থেকে ব্যবহারকারীর নাম এবং পাসওয়ার্ড সরবরাহ করে সীমান্ত একটি JWT টোকন পেতে পারে। প্রতিক্রিয়া এছাড়াও একটি প্রমাণীকরণ-স্থিতিটি, যা হয় হতে পারে অন্তর্ভুক্ত প্রামাণ বা PRE_AUTHENTICATED_MFA_REQUIRED

যদি ব্যবহারকারীকে এমএফএ প্রয়োজন হয় তবে টোকনটি একটি একক অনুমোদিত কর্তৃপক্ষ PRE_AUTHENTICATED_MFA_REQUIREDএবং 5 মিনিটের মেয়াদোত্তীকরণের সময় দিয়ে জারি করা হয় । এটি ব্যবহারকারীকে শেষ প্রান্তে অ্যাক্সেস করার অনুমতি দেয় /auth/mfa-tokenযেখানে তারা তাদের প্রমাণীকরণকারী অ্যাপ্লিকেশন থেকে TOTP কোড সরবরাহ করতে পারে এবং সাইটে অ্যাক্সেসের জন্য সম্পূর্ণরূপে অনুমোদন প্রাপ্ত টোকেন পেতে পারে।

সরবরাহকারী এবং টোকেন

আমি আমার প্রথা তৈরি করেছি MfaAuthenticationProviderযা প্রয়োগ করে AuthenticationProvider:

    @Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {
        // validate the OTP code
    }

    @Override
    public boolean supports(Class<?> authentication) {
        return OneTimePasswordAuthenticationToken.class.isAssignableFrom(authentication);
    }

এবং এটি OneTimePasswordAuthenticationTokenযা AbstractAuthenticationTokenব্যবহারকারীর নাম (স্বাক্ষরিত জেডাব্লুটি থেকে নেওয়া) এবং ওটিপি কোড ধরে রাখতে প্রসারিত ।

কনফিগ

আমি আমার রীতি আছে WebSecurityConfigurerAdapter, যেখানে আমি আমার কাস্টম যোগ AuthenticationProviderমাধ্যমে http.authenticationProvider()। জাভাডকের সাথে সংগতি রেখে এটি সঠিক জায়গা বলে মনে হচ্ছে:

ব্যবহার করার জন্য একটি অতিরিক্ত প্রমাণীকরণের সরবরাহকারী যুক্ত করার অনুমতি দেয়

আমার SecurityConfigদেখতে সম্পর্কিত প্রাসঙ্গিক অংশগুলি এটির মতো।

    @Configuration
    @EnableWebSecurity
    @EnableJpaAuditing(auditorAwareRef = "appSecurityAuditorAware")
    public class SecurityConfig extends WebSecurityConfigurerAdapter {
        private final TokenProvider tokenProvider;

        public SecurityConfig(TokenProvider tokenProvider) {
            this.tokenProvider = tokenProvider;
        }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authenticationProvider(new MfaAuthenticationProvider());

        http.authorizeRequests()
            // Public endpoints, HTML, Assets, Error Pages and Login
            .antMatchers("/", "favicon.ico", "/asset/**", "/pages/**", "/api/auth/token").permitAll()

            // MFA auth endpoint
            .antMatchers("/api/auth/mfa-token").hasAuthority(ROLE_PRE_AUTH_MFA_REQUIRED)

            // much more config

নিয়ামক

AuthControllerহয়েছে AuthenticationManagerBuilderইনজেকশনের এবং এটি সমস্ত একসঙ্গে টেনে করা হয়।

@RestController
@RequestMapping(AUTH)
public class AuthController {
    private final TokenProvider tokenProvider;
    private final AuthenticationManagerBuilder authenticationManagerBuilder;

    public AuthController(TokenProvider tokenProvider, AuthenticationManagerBuilder authenticationManagerBuilder) {
        this.tokenProvider = tokenProvider;
        this.authenticationManagerBuilder = authenticationManagerBuilder;
    }

    @PostMapping("/mfa-token")
    public ResponseEntity<Token> mfaToken(@Valid @RequestBody OneTimePassword oneTimePassword) {
        var username = SecurityUtils.getCurrentUserLogin().orElse("");
        var authenticationToken = new OneTimePasswordAuthenticationToken(username, oneTimePassword.getCode());
        var authentication = authenticationManagerBuilder.getObject().authenticate(authenticationToken);

        // rest of class

তবে এর বিরুদ্ধে পোস্ট /auth/mfa-tokenকরা এই ত্রুটির দিকে পরিচালিত করে:

"error": "Forbidden",
"message": "Access Denied",
"trace": "org.springframework.security.authentication.ProviderNotFoundException: No AuthenticationProvider found for de.....OneTimePasswordAuthenticationToken

কেন স্প্রিং সিকিউরিটি আমার প্রমাণীকরণ প্রদানকারী সরবরাহ করে না? নিয়ামককে ডিবাগ করা আমাকে দেখায় যে DaoAuthenticationProviderএটিই কেবলমাত্র প্রমাণীকরণ সরবরাহকারী AuthenticationProviderManager

আমি যদি আমার MfaAuthenticationProviderশিম হিসাবে প্রকাশ করি তবে এটি কেবলমাত্র সরবরাহকারী যা নিবন্ধীকৃত, তাই আমি বিপরীতটি পাই:

No AuthenticationProvider found for org.springframework.security.authentication.UsernamePasswordAuthenticationToken. 

সুতরাং, আমি কিভাবে উভয় পেতে?

আমার প্রশ্ন

AuthenticationProviderএকটি স্প্রিং বুট সিকিউরিটি স্টার্টার কনফিগার করা সিস্টেমে অতিরিক্ত সংহত করার প্রস্তাবিত উপায় কী , যাতে আমি DaoAuthenticationProviderএবং আমার নিজস্ব কাস্টম উভয়ই পাই MfaAuthenticationProvider? আমি স্প্রিং বুট স্কুরিরিটি স্টার্টারের ডিফল্ট রাখতে এবং অতিরিক্তভাবে আমার নিজস্ব সরবরাহকারী রাখতে চাই ।

রিপ্লে আক্রমণ প্রতিরোধ

আমি জানি যে ওটিপি অ্যালগরিদম কোডটি কার্যকর হওয়ার সময় স্লাইসের মধ্যে রিপ্লে আক্রমণ থেকে নিজেই সুরক্ষা দেয় না; আরএফসি 6238 এটি পরিষ্কার করে

প্রথম ওটিপি-র জন্য সফল বৈধতা জারি হওয়ার পরে যাচাইকারীকে ওটিপির দ্বিতীয় প্রয়াস গ্রহণ করতে হবে না, এটি কেবলমাত্র ওটিপি-র এককালীন ব্যবহার নিশ্চিত করে।

আমি ভাবছিলাম যে সুরক্ষা কার্যকর করার কোনও প্রস্তাবিত উপায় আছে কিনা। যেহেতু ওটিপি টোকেনগুলি সময় ভিত্তিক হয় আমি ব্যবহারকারীর মডেলটিতে সর্বশেষ সফল লগইনটি সংরক্ষণ করার এবং 30 সেকেন্ডের সময় স্লাইসে প্রতি একটাই সফল লগইন আছে কিনা তা নিশ্চিত করার কথা ভাবছি। এটি অবশ্যই ব্যবহারকারীর মডেলটিতে সিঙ্ক্রোনাইজেশন। এর চেয়ে ভাল কোন পন্থা?

ধন্যবাদ.

-

পিএস: যেহেতু এটি সুরক্ষা সম্পর্কে একটি প্রশ্ন তাই আমি বিশ্বাসযোগ্য এবং / অথবা অফিসিয়াল উত্স থেকে উত্তর অঙ্কনের সন্ধান করছি। ধন্যবাদ.

উত্তর:


0

আমার নিজের প্রশ্নের উত্তর দেওয়ার জন্য, আমি আরও গবেষণার পরে এইভাবে এটি প্রয়োগ করেছি।

আমি প্রয়োগ করি এমন একটি পোজো হিসাবে একটি সরবরাহকারী রয়েছে AuthenticationProvider। এটি ইচ্ছাকৃতভাবে বিন / উপাদান নয়। অন্যথায় বসন্ত এটি একমাত্র সরবরাহকারী হিসাবে নিবন্ধন করবে।

public class MfaAuthenticationProvider implements AuthenticationProvider {
    private final AccountService accountService;

    @Override
    public Authentication authenticate(Authentication authentication) {
        // here be code 
        }

আমার সিকিউরিটি কনফিগ-এ, আমি স্প্রিংকে স্বতঃশক্তি দিয়েছিলাম AuthenticationManagerBuilderএবং ম্যানুয়ালি আমার ইনজেকশন দেইMfaAuthenticationProvider

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
       private final AuthenticationManagerBuilder authenticationManagerBuilder;

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        // other code  
        authenticationManagerBuilder.authenticationProvider(getMfaAuthenticationProvider());
        // more code
}

// package private for testing purposes. 
MfaAuthenticationProvider getMfaAuthenticationProvider() {
    return new MfaAuthenticationProvider(accountService);
}

মান প্রমাণীকরণ পরে, যদি ব্যবহারকারী এমএফএ সক্ষম করেছে, তারা প্রাক একটি মঞ্জুর কর্তৃপক্ষের সঙ্গে প্রমাণীকৃত PRE_AUTHENTICATED_MFA_REQUIRED । এটি তাদের একটি একক শেষ পয়েন্ট অ্যাক্সেস করতে দেয় /auth/mfa-token,। এই শেষ পয়েন্টটি বৈধ জেডাব্লুটিটি এবং প্রদত্ত টিওটিপি থেকে ব্যবহারকারীর নাম নেয় এবং এটি authenticate()প্রমাণীকরণের ব্যবস্থাপনার বিলিডার পদ্ধতিতে প্রেরণ করে , যা MfaAuthenticationProviderএটি পরিচালনা করতে পারে হিসাবে এটি চয়ন করে OneTimePasswordAuthenticationToken

    var authenticationToken = new OneTimePasswordAuthenticationToken(usernameFromJwt, providedOtp);
    var authentication = authenticationManagerBuilder.getObject().authenticate(authenticationToken);
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.