“사용자는 관리자인지 여부를 결정해서는 안됩니다. 권한 또는 보안 시스템이 필요합니다.”


55

이 질문에 사용 된 예제는 최소한의 데이터를 함수에 전달 하여 사용자가 관리자인지 아닌지를 결정하는 가장 좋은 방법을 제공합니다. 일반적인 대답은 다음과 같습니다.

user.isAdmin()

이로 인해 여러 차례 반복되고 많은 투표가있었습니다.

사용자가 관리자인지 여부를 결정해서는 안됩니다. 권한 또는 보안 시스템이 있어야합니다. 클래스에 밀접하게 연결된다고해서 해당 클래스의 일부로 만드는 것이 좋은 생각은 아닙니다.

나는 대답했다.

사용자가 아무것도 결정하지 않습니다. User 객체 / 테이블은 각 사용자에 대한 데이터를 저장합니다. 실제 사용자는 자신에 대한 모든 것을 변경할 수 없습니다.

그러나 이것은 생산적이지 않았습니다. 분명히 의사 소통을 어렵게하는 근본적인 관점의 차이가 있습니다. 누군가 user.isAdmin ()이 왜 나쁜지 설명하고 "올바른"것에 대한 간단한 스케치를 그릴 수 있습니까?

실제로 보안이 보호되는 시스템에서 보안을 분리하는 이점을 보지 못했습니다. 모든 보안 텍스트는 보안이 처음부터 시스템에 설계되어야하며 개발, 배포, 유지 관리 및 수명 종료의 모든 단계에서 고려되어야한다고 말합니다. 측면에 볼트로 고정 할 수있는 것은 아닙니다. 그러나이 의견에 대해 지금까지 17 건의 투표가 중요한 것을 놓치고 있다고 말합니다.


8
특히 사용자 db 테이블의 플래그 일 경우 특히 나쁘지 않다고 생각합니다. 해야 미래의 변화가 미래에 변경합니다. 사용자 개체에서 보안 시스템을 호출 할 수도 있습니다. 한 번은 모든 db / resource 액세스가 현재 사용자 객체를 통과해야하는 디자인 패턴에 대해 읽었으며, 허용되지 않는 것을 시도하지 않도록해야합니다. 다소 많을 수 있지만 사용자는 모든 보안 관련 항목을 다루는 "권한"개체를 제공 할 수 있습니다.
Cephalopod 2018

오해가 있다고 생각합니다. 귀하를 위해 "사용자"는 소프트웨어를 사용하는 사람을 의미합니다. "사용자"란 사용자의 기능을 사용하는 코드를 의미합니다.
Philipp

2
요청한 것이 아니라이 경우 가장주의해야 할 것은 IsAdmin () 메서드입니다. 일반적으로 "관리자"를 하드 코딩하지 말고 가능한 권한 세트 만 있으면 "관리자"가 전체 세트를 갖도록하는 것이 좋습니다. 이렇게하면 나중에 관리자 역할을 분리해야 할 때 훨씬 쉽습니다. 그리고 특별한 경우 논리를 줄입니다.
psr

1
@Philipp 나는 그렇게 생각하지 않습니다 ... 두 사이트 모두 명시 적으로 방법을 사용 하여 User객체 에 대해 이야기하고 있습니다 isAdmin()(무엇보다 뒤에 무엇이든)
Izkata

편집하기에 너무 늦습니다. "양쪽 사이트"가 아니라 "양쪽"을 의미했습니다 ... = P
Izkata

답변:


12

사용자를 키로, 권한을 값으로 생각하십시오.

상황에 따라 사용자마다 권한이 다를 수 있습니다. 권한은 상황에 따라 다르므로 각 상황에 따라 사용자를 변경해야합니다. 따라서 해당 논리를 다른 곳에 (예 : 컨텍스트 클래스) 배치하고 필요한 경우 권한을 찾는 것이 좋습니다.

부작용은 시스템을 더 안전하게 만들 수 있다는 것입니다. 관련이없는 장소에 대해서는 관리자 플래그를 지우는 것을 잊을 수 없기 때문입니다.


40

그 의견은 잘못 표현되었습니다.

요점은 사용자 개체는 관리자, 시험 사용자, 수퍼 유저 또는인지 "결정"여부입니다 무엇이든 또는 일반의 아웃. 분명히 그것은 당신이 구현 한대로 소프트웨어 시스템이 큰 것을 결정하지 않습니다. 요점은 "사용자"여부 클래스가 해야 표현 의 객체가 나타내는 주체의 역할을, 또는이 있는지 다른 클래스의 책임입니다.


6
아야 (내 의견이었다),하지만 당신은 내가 한 것보다 훨씬 더 잘 넣습니다.
Marjan Venema

User 클래스가 아닌 별도의 Role 클래스에서 역할을 모델링한다고 말하고 있습니까? LDAP와 같은 별도의 시스템을 권장하지 않습니까? Role 클래스의 모든 단일 결정에 적절한 사용자 레코드를 쿼리해야하고 다른 정보가 필요하지 않은 경우 어떻게해야합니까? 여전히 사용자와 분리되어야합니까? 그렇다면 왜 그렇습니까?
GlenPeterson

2
@GlenPeterson : 클래스 <> 테이블 일 필요는 없으며 일반적으로 테이블보다 더 많은 클래스를 식별해야합니다. 데이터 지향적 인 것은 클래스에서 하위 목록을 정의하게하지만, 여러 번이 목록은 다른 "선원"(순서) 또는 사용자를 전달하는 일부 클래스 (또는 순서)에서 검색해야합니다. 동사와 명사보다 책임의 문제입니다.
Marjan Venema

9
사용자를 키로, 권한을 값으로 생각하십시오. 상황에 따라 사용자마다 권한이 다를 수 있습니다. 권한은 상황에 따라 다르므로 각 상황에 따라 사용자를 변경해야합니다. 따라서 해당 로직을 다른 곳에 배치하는 것이 좋습니다 (예 : 컨텍스트 클래스).
Wilbert

2
@ 윌버 트 : 상황! 그것은 특히 깨달음입니다! 예, 해당 권한에 대해 둘 이상의 컨텍스트가 있으면 모든 것이 의미가 있습니다. 일반적으로 이러한 권한을 단일 컨텍스트에서 볼 수 있으며이 경우 사용자에게 권한을 부여하는 것이 가장 간단한 솔루션입니다. 그들이 두 번째 맥락에서 다르게 적용된다면 분명히 그들은 거기에 속하지 않습니다. 당신이 대답으로 쓰면, 나는 그것을 받아 들일 것입니다. 감사합니다.
GlenPeterson

30

나는 원래의 의견을 그 말대로 표현하기로 선택하지 않았지만 잠재적으로 합법적 인 문제를 식별합니다 .

특히 분리를 보증하는 문제는 인증권한 입니다.

인증 은 로그인하고 신원을 얻는 과정을 말합니다. 시스템이 당신이 누구 인지 알고 개인화, 객체 소유권 등과 같은 것들에 사용되는 방식입니다.

승인귀하가 할 수있는 일을 말하며 , (일반적으로) 귀하가 누구 인지에 따라 결정 되지않습니다 . 대신 역할이나 권한과 같은 일부 보안 정책에 의해 결정되며 이름이나 전자 메일 주소와 같은 것을 신경 쓰지 않습니다.

이 두 가지는 서로 직교로 변할 수 있습니다. 예를 들어 OpenID / OpenAuth 공급자를 추가하여 인증 모델을 변경할 수 있습니다. 새 역할을 추가하거나 RBAC에서 ABAC로 변경하여 보안 정책을 변경할 수 있습니다.

이 모든 것이 하나의 클래스 또는 추상화로 들어가면 위험 완화를 위한 가장 중요한 도구 중 하나 인 보안 코드 가 아이러니하게도 위험에 처하게됩니다.

인증 및 권한 부여가 너무 밀접하게 결합 된 시스템에서 작업했습니다. 한 시스템에는 각각 한 유형의 "역할"에 대해 두 개의 병렬 사용자 데이터베이스가있었습니다. 이를 설계 한 개인 또는 팀은 단일 물리적 사용자가 두 역할에 모두 있거나 여러 역할에 공통적 인 특정 조치가 있거나 사용자 ID 충돌에 문제가있을 수 있다고 생각하지 않았습니다. 이것은 분명히 극단적 인 예이지만, 함께 일하는 것은 엄청나게 고통 스러웠습니다.

Microsoft 및 Sun / Oracle (Java)은 전체 인증 및 권한 부여 정보를 보안 주체라고 합니다. 완벽하지는 않지만 합리적으로 잘 작동합니다. 예를 들어, .NET에서는 전자 IPrincipal캡슐화 하고 IIdentity, 전자는 정책 (권한) 객체이고 후자는 신원 (인증)입니다. 당신은 합리적으로 하나를 넣어하기로 결정 의문을 제기 할 수 내부에 다른의를하지만, 중요한 것은이 때문이다 대부분의 코드는 추상화의 한위한 것 쓰기 가 테스트하고 리팩터링하기 쉬운 것을 의미한다.

A를 아무 문제 없습니다 User.IsAdmin필드 ... 하지 않는 한 또한이 User.Name필드. 이것은 "사용자"개념 이 제대로 정의되지 않았 음을 의미하며 , 안타깝게도 보안과 관련하여 귀에 약간 젖어있는 개발자들 사이에서 매우 흔한 실수입니다. 일반적으로 ID정책 으로 공유해야하는 유일한 것은 사용자 ID이며, 이는 우연히 Windows 및 * nix 보안 모델 모두에서 구현되는 방식입니다.

아이덴티티와 정책을 모두 캡슐화하는 래퍼 객체를 생성하는 것은 완전히 허용됩니다. 예를 들어, 현재 사용자가 액세스 할 수있는 다양한 위젯 또는 링크 외에 "hello"메시지를 표시해야하는 대시 보드 화면을 쉽게 만들 수 있습니다. 이 랩퍼 는 ID 및 정책 정보를 랩핑 하고 해당 정보를 소유한다고 주장하지 않는 한. 즉, 집계 루트 로 표시되지 않는 한 .

YAGNI 등으로 인해 새로운 애플리케이션을 처음 설계 할 때 단순한 보안 모델은 항상 좋은 생각처럼 보이지만 , 놀랍게도 새로운 기능이 추가되기 때문에 나중에 다시 물어 뜯는 경우가 거의 있습니다!

따라서 자신에게 가장 적합한 것을 알고 있으면 인증 및 권한 부여 정보를 별도로 유지하게됩니다. 지금 "권한 부여"가 "IsAdmin"플래그만큼 단순하더라도 인증 정보와 동일한 클래스 또는 테이블의 일부가 아닌 경우 보안 정책이 필요한 경우 이미 잘 작동하는 인증 시스템에서 재구성 수술을 수행 할 필요가 없습니다.


11
이 글을 쓸 시간이 있었으면 좋겠다. 그런 다음 다시 한 번 더 생각하지 않고 아마도 그것을 넣을 수 없었을 것입니다. 내 직감이 본능적으로 많은 길을 가고 있지만, 왜 나 자신이나 다른 사람에게 설명을 더 많이 생각하고 노력해야하는지 설명합니다. 이 게시물에 감사드립니다. 여러 번 플러스했을 것입니다,하지만 SE는 나를 못하게합니다 ...
Marjan Venema

이것은 내가 진행중인 프로젝트와 매우 흡사하게 들리며 귀하의 대답은 나에게 또 다른 관점을주었습니다. 정말 고맙습니다!
Brandon

"User.Name 필드가 없으면 User.IsAdmin 필드에는 아무 문제가 없습니다." 그러나 isAdmin방법은 무엇 입니까? 권한을 추적 할 책임이있는 개체에 위임 할 수도 있습니다. 관계형 모델을 디자인 할 때 모범 사례가 무엇인지 (엔터티가 가지고있는 필드) OO 모델에서 모범 사례가 무엇인지 (객체가 응답 할 수있는 메시지) 반드시 번역 가능한 것은 아닙니다.
KaptajnKold

@KaptajnKold :이 포럼의 다양한 Q & A 스레드에서이 정서를 계속 읽습니다. 메소드가 존재하는 경우 , 조작을 직접 수행하거나 위임 하는 것은 중요하지 않습니다. 다른 클래스가이를 사용할 수 있기 때문에 여전히 책임으로 간주됩니다 . 당신의 User.IsAdmin힘은 아주 잘 호출하지만 아무것도하지 않는 한 줄 수 PermissionManager.IsAdmin(this.Id)있지만, 30 개 다른 클래스에 의해 참조됩니다, 당신은 변경하거나 제거 할 수 없습니다. 이것이 SRP가 존재하는 이유입니다.
Aaronaught

그리고 @KaptajnKold, 관계형 모델에 관한 한, 나는 당신이 무엇을 얻고 있는지 잘 모르겠습니다. 필드 를 갖는 것이 더 나쁩니다 . 시스템이 RBAC 또는 더 복잡한 것으로 발전한 후 오래 지속되는 경향이있는 분야이며 점차 "실제"권한과 동기화되지 않으며 사람들은 더 이상 사용하지 않아야한다는 사실을 잊어 버립니다. 그리고 ... 글쎄요 "admin"과 "non-admin"의 두 가지 역할 만 있다고 생각하더라도 부울 / 비트 필드로 저장하지 말고 올바르게 정규화하고 권한 테이블을 갖습니다. IsAdmin
Aaronaught

28

글쎄, 최소한 단일 책임 원칙을 위반 하는 것 입니다. 변경이있을 경우 (여러 관리자 수준, 훨씬 더 다른 역할?) 이런 종류의 디자인은 상당히 지저분하고 유지하기가 끔찍할 것입니다.

보안 시스템을 사용자 클래스와 분리하여 두 가지 역할을 모두 정의 할 수있는 이점을 고려하십시오. 더 깨끗하고 유지 관리하기 쉬운 디자인으로 마무리합니다.


2
@GlenPeterson : 아니요, 사용자는 보안 없이도 존재할 수 있습니다. 내 이름, 표시 이름, 주소, 전자 메일 주소 등은 어디에 있습니까? 식별 (인증)과 인증은 모두 다른 짐승입니다.
Marjan Venema

2
class User식별, 인증, 인증 의 보안 삼중 항의 핵심 구성 요소입니다 . 이것들은 디자인 수준에서 밀접하게 연결되어 있기 때문에 코드가 이러한 상호 의존성을 반영하는 것은 부당하지 않습니다.
MSalters

1
문제는 User 클래스에 삼중 항 처리에 대한 모든 논리가 포함되어 있어야합니다!
Zavior

3
@MSalters : 그것이 그러한 논리에 대한 API라면, 정확한 논리를 위해 다른 곳을 위임하더라도 그것에 대해 알고 있습니다. 요점은 승인 (권한)이 사용자와 다른 것의 조합에 관한 것이며 따라서 사용자 나 다른 것의 일부가 아니라 사용자와 다른 것을 올바르게 인식하는 권한 시스템의 일부 여야한다는 것입니다. 에 대한 권한이 부여되었습니다.
Marjan Venema

2
Should there be changes글쎄, 우리는 변화가 있을지 모른다. 야그 니와 모두. 필요할 때 변경 사항이 있습니까?
이즈 카타

10

어쩌면 잘못 표현 된 문제는 User수업 에 너무 많은 비중을 두는 것 입니다. 아니요, User.isAdmin()해당 의견에서 제안한 것처럼 방법을 사용하는 데 보안 문제가 없습니다 . 결국, 핵심 클래스 중 하나에 악의적 인 코드를 삽입하기에 충분한 코드를 가진 사람이 있다면 심각한 문제가 있습니다. 반면 User에 모든 컨텍스트의 관리자인지 여부를 결정하는 것은 이치에 맞지 않습니다 . 포럼의 중재자, 첫 페이지에 게시물을 게시 할 수있는 편집자, 편집자가 게시 할 내용을 쓸 수있는 작성자 등 다른 역할을 추가한다고 상상해보십시오. User객체 에 배치하는 방법 User을 사용하면 클래스와 직접 관련이없는 너무 많은 메소드와 너무 많은 논리 가 생길 수 있습니다.

대신 다른 유형의 권한 열거 형과 PermissionsManager클래스를 사용할 수 있습니다 . 아마도 PermissionsManager.userHasPermission(User, Permission)부울 값을 반환하는 것과 같은 메소드를 가질 수 있습니다 . 실제로는 (Java에서) 다음과 같이 보일 수 있습니다.

if (!PermissionsManager.userHasPermission(user, Permissions.EDITOR)) {
  Site.renderSecurityRejectionPage();
}

이는 실제로 Rails 방법과 동일 before_filter하며, 실제 환경에서 이러한 유형의 권한 검사 예를 제공합니다.


6
user.hasPermission(Permissions.EDITOR)OO 대신 더 장황하고 절차 적이라는 점을 제외하고 는 어떻게 다른 가요?
Cephalopod

9
@Arian : user.hasPermissions사용자 클래스에 너무 많은 책임이 있기 때문 입니다. 권한에 대해 알 필요가있는 반면 사용자 (클래스)는 그러한 지식 없이도 존재할 수 있어야합니다. 사용자 클래스가 인쇄하거나 표시하는 방법 (양식 작성)에 대해 알지 못하도록하려면 프린터 렌더러 / 빌더 또는 표시 렌더러 / 빌더 클래스에 그대로 두십시오.
Marjan Venema

4
user.hasPermission(P)올바른 API이지만 인터페이스 일뿐입니다. 실제 결정은 물론 보안 서브 시스템에서 이루어져야합니다. 테스트에 대한 syrion의 의견을 해결하기 위해 테스트 중에 해당 서브 시스템을 교체 할 수 있습니다. 그러나 간단한 장점은 user.hasPermission(P)테스트 할 수 있도록 모든 코드를 오염시키지 않는다는 것 class User입니다.
MSalters

3
@MarjanVenema 그 논리에 의해, 사용자는 전혀 책임이없는 데이터 객체로 남아있을 것입니다. 복잡한 시스템이 필요한 경우 전체 권한 관리를 사용자 클래스에서 구현해야한다는 말은 아닙니다 . 사용자가 권한에 대해 알 필요는 없지만 다른 모든 클래스가 사용자의 권한을 해결하는 방법을 알아야하는 이유는 알 수 없습니다. 이것은 조롱과 테스트를 훨씬 더 어렵게 만듭니다.
Cephalopod 2018

6
@Arian : 빈혈 클래스는 냄새가 있지만 일부 클래스에는 동작이 없습니다 ... 사용자, imho는 다른 것들에 대한 매개 변수로 더 잘 사용되는 클래스 중 하나입니다. (어떻게 요청하는지에 따라 결정을 내리십시오.)
Marjan Venema

9

Object.isX ()는 객체와 X 사이의 명확한 관계를 나타내는 데 사용되며 부울 결과로 표시 될 수 있습니다. 예를 들면 다음과 같습니다.

Water.isBoiling ()

Circuit.isOpen ()

User.isAdmin ()은 시스템의 모든 컨텍스트 내에서 '관리자'라는 단일 의미를 가정 합니다. 사용자는 시스템의 모든 부분에서 관리자입니다.

간단하게 들리지만 실제 프로그램은이 모델에 맞지 않을 것입니다. 사용자가 [X] 리소스를 관리해야하지만 [Y]는 아니고보다 뚜렷한 유형의 관리자 ([프로젝트])가 있어야합니다. ] 관리자 대 [시스템] 관리자).

이 상황에서는 일반적으로 요구 사항을 조사해야합니다. 클라이언트가 User.isAdmin ()이 실제로 나타내는 관계를 원하는 경우는 거의 없으므로 설명없이 그러한 솔루션을 구현하는 것을 망설이지 않습니다.


6

포스터는 단순히 다르고 복잡한 디자인을 염두에 두었습니다. 제 생각 User.isAdmin()에는 괜찮습니다 . 나중에 복잡한 권한 모델을 소개하더라도 움직일 이유가 거의 없습니다 User.isAdmin(). 나중에 User 클래스를 로그인 한 사용자를 나타내는 객체와 사용자에 대한 데이터를 나타내는 정적 객체로 분할 할 수 있습니다. 그렇지 않을 수도 있습니다. 내일을 위해 내일을 구하십시오.


4
Save tomorrow for tomorrow. 네. 방금 작성한 밀접하게 결합 된 코드가 비둘기를 ed다는 것을 알면 분리하기 위해 20 분이 더 걸리지 않기 때문에 코드를 다시 작성해야합니다 ...
MirroredFate

5
@MirroredFate : User.isAdminUser 클래스를 특정 메커니즘에 연결하지 않고 임의의 권한 메커니즘에 메소드를 연결 하는 것이 전적으로 가능합니다 .
케빈 클라인

3
User.isAdmin을 특정 메커니즘에 연결하지 않아도 임의의 권한 메커니즘에 연결하려면 잘 ... 커플 링이 필요합니다. 인터페이스에 대한 최소값입니다. 그리고 그 인터페이스는 단순히 존재해서는 안됩니다. 그것은 사용자 클래스 (및 인터페이스)에게 단순히 책임을지지 않아야 할 것을 제공합니다. Aaronaught 는 (이 질문에 대한 다른 모든 답변의 조합과 마찬가지로) 내가 할 수있는 것보다 훨씬 잘 설명합니다.
Marjan Venema

8
@MirroredFate : 더 복잡한 요구 사항을 충족하기 위해 간단한 구현을 다시 작성해야하는지 상관하지 않습니다. 그러나 나는 결코 일어나지 않을 것으로 예상되는 미래의 요구 사항을 충족하도록 설계된 지나치게 복잡한 API에 대해 정말 나쁜 경험을했습니다.
케빈 클라인

3
@kevincline 지나치게 복잡한 API는 (정의 적으로는) 나쁜 일이지만 지나치게 복잡한 API를 작성해야한다고 제안하지는 않았습니다. Save tomorrow for tomorrow시스템이 제대로 구현되지 않으면 사소한 문제가 발생하기 때문에 끔찍한 디자인 방식 이라고 말하고 있었습니다. 사실, 이러한 사고 방식은 초기 불량 설계를 패치하기 위해 레이어 온 레이어가 추가되므로 지나치게 복잡한 API를 생성합니다. 나는 나의 입장이 같다고 생각한다 measure twice, cut once.
MirroredFate

5

실제로 문제는 아닙니다 ...

에 문제가 없습니다 User.isAdmin(). 나는 PermissionManager.userHasPermission(user, permissions.ADMIN)SRP라는 거룩한 이름으로 코드를 덜 명확하게 만들고 가치있는 것을 추가하지 않는 것과 같은 것을 선호합니다 .

나는 SRP가 문자 그대로 조금 해석되고 있다고 생각합니다. 클래스가 풍부한 인터페이스를 갖는 것이 좋습니다. SRP는 개체가 단일 책임에 속하지 않는 모든 것을 공동 작업자에게 위임해야 함을 의미합니다. 사용자의 관리자 역할이 부울 필드보다 관련이있는 경우 사용자 개체가 PermissionsManager에 위임하는 것이 좋습니다. 그러나 이것이 사용자가 isAdmin방법 을 유지하는 것이 좋지 않다는 것을 의미하지는 않습니다 . 실제로 이는 응용 프로그램이 단순에서 복합으로 졸업 할 때 User 개체를 사용하는 코드를 변경해야 함을 의미합니다. IOW는 고객이 관리자인지 여부에 대한 질문에 답변하기 위해 실제로 필요한 것이 무엇인지 알 필요가 없습니다.

...하지만 왜 정말로 알고 싶습니까?

즉, 위젯 업데이트와 같이 사용자가 특정 작업을 수행 할 수 있는지 여부와 같은 다른 질문에 대답 할 수있는 것을 제외하고는 사용자가 관리자인지 알 필요가 거의없는 것 같습니다. 이 경우 위젯에 다음과 같은 메소드를 사용하는 것이 좋습니다 isUpdatableBy(User user).

boolean isUpdatableBy(User user) {
    return user.isAdmin();
}

이렇게하면 위젯이 사용자가 업데이트하기 위해 충족해야하는 기준을 알 수 있으며, 관리자인지는 사용자가 알아야합니다. 이 디자인은 의도에 대해 명확하게 전달하며,시기와시기에보다 복잡한 비즈니스 로직으로 쉽게 졸업 할 수 있습니다.

[편집하다]

의 문제 되지 가지고 User.isAdmin()및 사용PermissionManager.userHasPermission(...)

사용자가 관리자 (또는 관리자 역할)인지 알고 싶다면 PermissionManager 객체에서 메소드를 호출하는 것보다 User 객체에서 메소드를 호출하는 것을 선호하는 이유를 설명하기 위해 내 대답에 추가 할 것이라고 생각했습니다.

이 사용자가 관리자 라는 질문을 할 때마다 항상 User 클래스에 의존한다고 가정하는 것이 공정하다고 생각합니다 . 그것은 당신이 제거 할 수없는 의존성입니다. 그러나 질문을하기 위해 사용자를 다른 개체로 전달해야하는 경우 사용자에게 이미있는 개체 위에 해당 개체에 대한 새로운 종속성을 만듭니다. 질문이 많으면 추가 종속성을 만드는 곳이 많으며 종속성 중 하나가 필요로 할 경우 변경해야 할 곳이 많습니다.

의존성을 User 클래스로 옮기는 것과 이것을 비교하십시오. 이제 갑자기 클라이언트 코드 (질문을 요구 해야하는 코드 는이 사용자는 admin ) 가이 질문에 대한 답변의 구현과 관련이없는 시스템이 있습니다. 권한 시스템을 자유롭게 변경할 수 있으며 한 클래스에서 하나의 메소드 만 업데이트하면됩니다. 모든 클라이언트 코드는 동일하게 유지됩니다.

isAdmin권한 하위 시스템에 대한 User 클래스의 종속성을 생성하는 것에 대한 두려움에 대해 사용자에 대한 메소드가 없다는 것을 주장하는 것은 1 달러를 벌기 위해 달러를 소비하는 것과 비슷합니다. 물론 User 클래스에서 하나의 종속성을 피할 수는 있지만 질문을해야하는 모든 위치에서 하나를 작성해야합니다. 좋은 거래는 아닙니다.


2
"SRP는 개체가 단일 책임에 속하지 않는 모든 것을 공동 작업자에게 위임해야 함을 의미합니다 . "- false . SRP에의 정의는 물체가 직접 수행 모든 것을 포함 하고 대표단이 모든 것을. 한 작업 만 직접 수행하지만 위임을 통해 간접적으로 50 개의 다른 작업을 수행하는 클래스는 여전히 SRP를 위반하고 있습니다.
Aaronaught

KaptajnKold : 나는 당신과 동의하기 때문에 +1하고 그것에 대해 약간의 죄책감을 느낍니다. 귀하의 게시물이 토론에 추가되지만 질문에 답변하지 않습니다.
GlenPeterson

@GlenPeterson 글쎄, 나는 "올바른 것처럼 보이는 것"이라는 질문의 일부를 다루려고 노력했다. 또한 : 당신은 나에게 동의하는 것에 대해 죄책감을 느끼지 말아야한다 :)
KaptajnKold

1
@JamesSnell 아마도. 만약. 그러나 그것은 여전히 ​​사용자의 isAdmin 메소드 내에서 제한 할 구현 세부 사항입니다. 그렇게하면 사용자의 "관리자"가 부울 필드에서보다 고급 인 것으로 진화 할 때 클라이언트 코드를 변경할 필요가 없습니다. 사용자가 관리자인지 알아야하는 많은 장소가있을 수 있으며 권한 부여 시스템이 변경 될 때마다 사용자를 변경하지 않아도됩니다.
KaptajnKold

1
@JamesSnell 어쩌면 서로 오해 할까? 의 문제 는 사용자가 관리자인지 여부는 의 문제와 동일하지 않습니다 사용자가 특정 작업을 수행하는 것이 허용되는지 여부 . 첫 번째 질문에 대한 답은 항상 문맥과 무관합니다. 두 번째 대답은 상황에 따라 크게 달라집니다. 이것이 원래 답변의 후반부에서 다루려고했던 것입니다.
KaptajnKold

1

이 토론은 Eric Lippert의 블로그 게시물을 상기시켜 주었으며 클래스 디자인, 보안 및 정확성에 대한 비슷한 토론에서 주목을 받았습니다.

왜 많은 프레임 워크 클래스가 봉인되어 있습니까?

특히 Eric은 다음과 같이 지적합니다.

4) 안전합니다. 다형성의 요점은 동물처럼 보이지만 실제로 기린 인 물체를 전달할 수 있다는 것입니다. 여기에는 잠재적 인 보안 문제가 있습니다.

봉인되지 않은 유형의 인스턴스를 취하는 메소드를 구현할 때마다 해당 유형의 적대적 인스턴스에 직면 할 때 해당 메소드를 강력하게 작성해야합니다. 적대적인 웹 페이지가 구현의 서브 클래스를 생성하고, 가상 메소드를 재정 의하여 논리를 어지럽히고 전달하는 작업을 수행 할 수 있기 때문에 구현에 대해 사실을 알고있는 불변에 의존 할 수 없습니다. 클래스를 봉인 할 때마다 , 나는 그 클래스가하는 일을 알고 있다는 확신을 가지고 그 클래스를 사용하는 메소드를 작성할 수 있습니다.

이것은 접선처럼 보이지만 다른 포스터가 SOLID 단일 책임 원칙에 대해 제기 한 점과 관련이 있다고 생각합니다 . User.IsAdmin메서드 나 속성 을 구현하지 않는 이유로 다음 악성 클래스를 고려하십시오 .

public class MyUser : User
{

    public new boolean IsAdmin()
    {
        // You know it!
        return true;
    }

    // Anything else we can break today?

}

물론, 그것은 약간의 확장입니다. 아직 IsAmdmin가상 방법을 제안하지는 않았지만 사용자 / 역할 아키텍처가 매우 복잡해지면 일어날 수 있습니다. (혹은 그렇지 않을 public class Admin : User { ... }수도 있습니다 . 고려해보십시오 . 그러한 클래스에는 위의 코드가 정확히있을 수 있습니다.) 악성 바이너리를 제자리에 배치하는 것은 일반적인 공격 경로가 아니며 모호한 사용자 라이브러리보다 혼란을 일으킬 가능성이 훨씬 높습니다. 실제 shenanigans의 문을 여는 Privilege Escalation 버그 일 수 있습니다 . 마지막으로 악의적 인 바이너리 또는 개체 인스턴스가 런타임에 들어간 경우 "Privilege 또는 Security System"이 비슷한 방식으로 대체되는 것은 그리 쉬운 일이 아닙니다.

그러나 Eric을 염두에두고 사용자 코드를 특정 유형의 취약한 시스템에 넣으면 게임을 잃어 버릴 수 있습니다.

아, 그리고 기록을 정확하게하기 위해, 나는 질문에 대한 가정에 동의합니다.“사용자는 그것이 관리자인지 아닌지를 결정해서는 안됩니다. 권한 또는 보안 시스템이 필요합니다.”시스템 User.IsAdmin에서 코드를 실행하는 경우 코드를 100 % 제어하지 않는 방법은 좋지 않습니다 Permissions.IsAdmin(User user). 대신 수행해야합니다 .


응? 이게 어떻습니까? 보안 정책의 위치에 관계없이 항상 안전하지 않은 것으로 하위 클래스를 분류 할 수 있습니다. 그것이 사용자, 교장, 정책, PermissionSet 등 무엇이든 중요하지 않습니다. 완전히 관련이없는 문제입니다.
Aaronaught

단일 책임을지지하는 보안 주장입니다. 요점에 직접 대답하기 위해 보안 및 권한 모듈은 봉인 된 클래스가 될 수 있지만 특정 디자인은 User 클래스가 가상 및 상속되기를 원할 수 있습니다. 블로그 기사의 마지막 요점입니다 (따라서 가장 가능성이 낮거나 중요하지는 않습니까?). 문제를 조금 혼란스럽게 생각하고 있지만 소스를 감안할 때 다형성이 보안 위협이 될 수 있으므로 책임을 제한한다는 것이 분명합니다. 주어진 클래스 / 객체가 더 안전합니다.
Patrick M

왜 그렇게 말했는지 모르겠습니다. 많은 보안 및 권한 프레임 워크는 확장 성이 뛰어납니다. 보안 (등 IPrincipal, IIdentity, ClaimSet에) 관련 핵심 .NET 유형의 대부분은되지 않습니다 하지 봉인하지만 당신은 당신이 원하는대로를 연결 할 수 있도록 사실 인터페이스 나 추상 클래스에 있습니다. Eric이 말하는 System.String것은 모든 종류의 중요한 프레임 워크 코드가 작동 방식에 대해 매우 구체적인 가정을하기 때문에 상속 할 수있는 것을 원하지 않는다는 것 입니다. 실제로, 대부분의 "사용자 코드"(보안 포함)는 테스트 배가를 허용하기 위해 상속 가능합니다.
Aaronaught

1
어쨌든, 다형성은 질문의 어느 곳에서도 언급되지 않으며, 원래 의견이 작성된 곳으로 저자의 링크를 따르면, 그것은 상속이나 클래스 불변성을 일반적으로 언급하지 않았 음을 분명히합니다-그것은 책임에 관한 것입니다.
Aaronaught

나는 그것이 언급되지 않았다는 것을 알고 있지만, 수업 책임의 원칙은 다형성과 직접 관련이 있습니다. IsAdmin재정의 / 동기화 할 수 있는 방법 이 없다면 잠재적 인 보안 허점이 없을 것입니다. 그 시스템 인터페이스의 방법을 검토 IPrincipal하고 IIdentity, 그것은 디자이너가 나와 함께 동의하고, 그래서 나는이 점을 인정하는 것이 분명하다.
Patrick M

0

여기서 문제는 다음과 같습니다.

if (user.isAdmin()) {
   doPriviledgedOp();
} else {
   // maybe we can anyway!
   doPriviledgedOp();
}

권한이있는 메소드가 호출자에게 충분한 권한이 있는지 확인해야하는 경우 보안을 올바르게 설정했는지 확인하십시오.이 경우 점검이 불필요한 것입니다. 또는 보안에 대한 자체 결정을 내릴 수있는 권한이없는 클래스를 가지고 있지 않거나 신뢰하지 않습니다.


4
특권이없는 수업은 무엇입니까?
Brandon

1
이런 종류의 코드가 작성되는 것을 막기 위해 실제로 할 수있는 일은 없습니다. 앱을 어떻게 디자인하든, 어딘가에 이와 같은 명시적인 검사 있을 것이며 누군가 가 안전하지 않은 것으로 작성할 수 있습니다. 권한 또는 시스템이 역할 또는 권한 속성으로 메소드를 장식하는 것처럼 권한 시스템이 간소화 된 경우에도 누군가 "공개"또는 "모든 사람"권한을 잘못 던질 수 있습니다. 그래서 이것이 어떻게 메소드가 User.IsAdmin 구체적 으로 문제를 일으키는 지 실제로는 알지 못합니다 .
Aaronaught
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.